From ded4840f6680ee83e1a654e716df048395cd03cd Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Wed, 15 Jan 2025 11:21:03 -0500 Subject: [PATCH 001/146] data: Update screenshots This also updates the screenshots from `data/appstream` to `data/screenshots`. --- data/appstream/1.png | Bin 24044 -> 0 bytes data/appstream/2.png | Bin 45356 -> 0 bytes data/appstream/3.png | Bin 62335 -> 0 bytes data/appstream/4.png | Bin 63930 -> 0 bytes data/appstream/5.png | Bin 30815 -> 0 bytes data/appstream/screenshot.png | Bin 107726 -> 0 bytes data/com.usebottles.bottles.metainfo.xml.in.in | 12 ++++++------ data/screenshots/1.png | Bin 0 -> 47293 bytes data/screenshots/2.png | Bin 0 -> 186393 bytes data/screenshots/3.png | Bin 0 -> 74362 bytes data/screenshots/4.png | Bin 0 -> 54570 bytes data/screenshots/5.png | Bin 0 -> 79786 bytes data/screenshots/6.png | Bin 0 -> 74878 bytes 13 files changed, 6 insertions(+), 6 deletions(-) delete mode 100644 data/appstream/1.png delete mode 100644 data/appstream/2.png delete mode 100644 data/appstream/3.png delete mode 100644 data/appstream/4.png delete mode 100644 data/appstream/5.png delete mode 100644 data/appstream/screenshot.png create mode 100644 data/screenshots/1.png create mode 100644 data/screenshots/2.png create mode 100644 data/screenshots/3.png create mode 100644 data/screenshots/4.png create mode 100644 data/screenshots/5.png create mode 100644 data/screenshots/6.png diff --git a/data/appstream/1.png b/data/appstream/1.png deleted file mode 100644 index 2f05b01505a13fdf19037327d8ba17008847b534..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24044 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 diff --git a/data/appstream/4.png b/data/appstream/4.png deleted file mode 100644 index e581db57a37932f83ef35d04b14854301edeac4f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 63930 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%0D}Eh7_=0bbJc^kFN=@@#z!V4R@cSt%cfrJD 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 pzjoCqR@cC7_}r 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 diff --git a/data/appstream/screenshot.png b/data/appstream/screenshot.png deleted file mode 100644 index 287173df142c073597a9250665b4de9d0a35df49..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 107726 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 DQzre% diff --git a/data/com.usebottles.bottles.metainfo.xml.in.in b/data/com.usebottles.bottles.metainfo.xml.in.in index 2fafd552959..941d5858623 100644 --- a/data/com.usebottles.bottles.metainfo.xml.in.in +++ b/data/com.usebottles.bottles.metainfo.xml.in.in @@ -31,22 +31,22 @@ - https://raw.githubusercontent.com/bottlesdevs/Bottles/main/data/appstream/screenshot.png + https://raw.githubusercontent.com/bottlesdevs/Bottles/main/data/screenshots/1.png - https://raw.githubusercontent.com/bottlesdevs/Bottles/main/data/appstream/1.png + https://raw.githubusercontent.com/bottlesdevs/Bottles/main/data/screenshots/2.png - https://raw.githubusercontent.com/bottlesdevs/Bottles/main/data/appstream/2.png + https://raw.githubusercontent.com/bottlesdevs/Bottles/main/data/screenshots/3.png - https://raw.githubusercontent.com/bottlesdevs/Bottles/main/data/appstream/3.png + https://raw.githubusercontent.com/bottlesdevs/Bottles/main/data/screenshots/4.png - https://raw.githubusercontent.com/bottlesdevs/Bottles/main/data/appstream/4.png + https://raw.githubusercontent.com/bottlesdevs/Bottles/main/data/screenshots/5.png - https://raw.githubusercontent.com/bottlesdevs/Bottles/main/data/appstream/5.png + https://raw.githubusercontent.com/bottlesdevs/Bottles/main/data/screenshots/6.png @APP_ID@ diff --git a/data/screenshots/1.png b/data/screenshots/1.png new file mode 100644 index 0000000000000000000000000000000000000000..1844b7c84eff61db65a90d8671b221886f0c9d5d GIT binary patch literal 47293 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º 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 Dj3!K4 literal 0 HcmV?d00001 diff --git a/data/screenshots/2.png b/data/screenshots/2.png new file mode 100644 index 0000000000000000000000000000000000000000..7f55a941933ea3ad4a0079fc082a158021d8f38e GIT binary patch literal 186393 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


RhrWm-3yQD4IO$g$XO*i;yliu|t)@j@tQ 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

EJhS}H?R{C706|mMUg)1& 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 kBz4 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 literal 0 HcmV?d00001 diff --git a/data/screenshots/4.png b/data/screenshots/4.png new file mode 100644 index 0000000000000000000000000000000000000000..4f0216624b2b3eb6f04da6abc9727dd6c5b6d144 GIT binary patch literal 54570 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 literal 0 HcmV?d00001 diff --git a/data/screenshots/6.png b/data/screenshots/6.png new file mode 100644 index 0000000000000000000000000000000000000000..86a0fa64d87586d2eeb40a608df395674aad1fe1 GIT binary patch literal 74878 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ⅇ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 TG1y4tg4$Q~FBfXwy#IdyeK0Z$ literal 0 HcmV?d00001 From d0d35d63f4f760400b9fcfbe2b61b8d218d10bef Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Wed, 15 Jan 2025 11:31:33 -0500 Subject: [PATCH 002/146] appstream: Add brand colors --- data/com.usebottles.bottles.metainfo.xml.in.in | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/data/com.usebottles.bottles.metainfo.xml.in.in b/data/com.usebottles.bottles.metainfo.xml.in.in index 941d5858623..7d76f2be708 100644 --- a/data/com.usebottles.bottles.metainfo.xml.in.in +++ b/data/com.usebottles.bottles.metainfo.xml.in.in @@ -10,6 +10,10 @@ Bottles Contributors + + #f4c8cb + #892119 +

Bottles lets you run Windows software on Linux, such as applications and games. It introduces a workflow that helps you organize by categorizing each software to your liking. Bottles provides several tools and integrations to help you manage and optimize your applications.

Features:

From b9f37e17d6af5b98d30519f65cb80eff34b7877e Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Wed, 15 Jan 2025 11:32:55 -0500 Subject: [PATCH 003/146] appstream: Update developer name This also removes the `` tag, as it's deprecated. --- data/com.usebottles.bottles.metainfo.xml.in.in | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/data/com.usebottles.bottles.metainfo.xml.in.in b/data/com.usebottles.bottles.metainfo.xml.in.in index 7d76f2be708..b834a98ec3c 100644 --- a/data/com.usebottles.bottles.metainfo.xml.in.in +++ b/data/com.usebottles.bottles.metainfo.xml.in.in @@ -6,9 +6,8 @@ @APP_ID@.desktop Bottles Run Windows Software - Bottles Contributors - Bottles Contributors + The Bottles Contributors #f4c8cb From 7d550495e2fbd40183afc252b5e1cd79fa75cdef Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Wed, 15 Jan 2025 11:45:46 -0500 Subject: [PATCH 004/146] appstream: Use sentence case for summary See: https://docs.flathub.org/docs/for-app-authors/metainfo-guidelines/quality-guidelines/#no-weird-formatting-1 --- data/com.usebottles.bottles.metainfo.xml.in.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/com.usebottles.bottles.metainfo.xml.in.in b/data/com.usebottles.bottles.metainfo.xml.in.in index b834a98ec3c..71119363e4e 100644 --- a/data/com.usebottles.bottles.metainfo.xml.in.in +++ b/data/com.usebottles.bottles.metainfo.xml.in.in @@ -5,7 +5,7 @@ @APP_ID@ @APP_ID@.desktop Bottles - Run Windows Software + Run Windows software The Bottles Contributors From 1f1dc750ab2d00ff67f687216bdfa3b1e2415d7c Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Wed, 15 Jan 2025 11:52:49 -0500 Subject: [PATCH 005/146] appstream: Add screenshot captions --- data/com.usebottles.bottles.metainfo.xml.in.in | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/data/com.usebottles.bottles.metainfo.xml.in.in b/data/com.usebottles.bottles.metainfo.xml.in.in index 71119363e4e..4a337b219ed 100644 --- a/data/com.usebottles.bottles.metainfo.xml.in.in +++ b/data/com.usebottles.bottles.metainfo.xml.in.in @@ -35,21 +35,27 @@ https://raw.githubusercontent.com/bottlesdevs/Bottles/main/data/screenshots/1.png + Bottles List Page https://raw.githubusercontent.com/bottlesdevs/Bottles/main/data/screenshots/2.png + Library Page https://raw.githubusercontent.com/bottlesdevs/Bottles/main/data/screenshots/3.png + Create New Bottle https://raw.githubusercontent.com/bottlesdevs/Bottles/main/data/screenshots/4.png + Bottle Details Page https://raw.githubusercontent.com/bottlesdevs/Bottles/main/data/screenshots/5.png + Bottle Settings Page https://raw.githubusercontent.com/bottlesdevs/Bottles/main/data/screenshots/6.png + Installers Page @APP_ID@ From 02f669b9da0fe959feec96c9ed13914f62ea2742 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Sun, 12 Jan 2025 09:10:48 -0500 Subject: [PATCH 006/146] bottle-row: Rename to BottleRow --- bottles/frontend/ui/bottle-row.blp | 2 +- bottles/frontend/views/list.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/bottles/frontend/ui/bottle-row.blp b/bottles/frontend/ui/bottle-row.blp index 163900eab29..2ab37e66eef 100644 --- a/bottles/frontend/ui/bottle-row.blp +++ b/bottles/frontend/ui/bottle-row.blp @@ -1,7 +1,7 @@ using Gtk 4.0; using Adw 1; -template $BottlesBottleRow: Adw.ActionRow { +template $BottleRow: Adw.ActionRow { activatable: true; use-markup: false; diff --git a/bottles/frontend/views/list.py b/bottles/frontend/views/list.py index 43ab9c226b4..24fb30b9e95 100644 --- a/bottles/frontend/views/list.py +++ b/bottles/frontend/views/list.py @@ -30,8 +30,8 @@ @Gtk.Template(resource_path="/com/usebottles/bottles/bottle-row.ui") -class BottlesBottleRow(Adw.ActionRow): - __gtype_name__ = "BottlesBottleRow" +class BottleRow(Adw.ActionRow): + __gtype_name__ = "BottleRow" Adw.init() @@ -191,7 +191,7 @@ def update_bottles_list(self, *args) -> None: self.bottle_status.set_visible(is_empty_local_bottles) for name, config in local_bottles.items(): - _entry = BottlesBottleRow(self.window, config) + _entry = BottleRow(self.window, config) self.__bottles[config.Path] = _entry if config.Environment != "Steam": From 5f238b7780bfc554d6746385a220abe8017320c8 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Sun, 12 Jan 2025 09:11:50 -0500 Subject: [PATCH 007/146] new-bottle-dialog: Rename to NewBottleDialog --- bottles/frontend/ui/new-bottle-dialog.blp | 2 +- bottles/frontend/views/new_bottle_dialog.py | 4 ++-- bottles/frontend/windows/window.py | 4 ++-- po/POTFILES | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/bottles/frontend/ui/new-bottle-dialog.blp b/bottles/frontend/ui/new-bottle-dialog.blp index 8f958f33962..654edb6bc55 100644 --- a/bottles/frontend/ui/new-bottle-dialog.blp +++ b/bottles/frontend/ui/new-bottle-dialog.blp @@ -1,7 +1,7 @@ using Gtk 4.0; using Adw 1; -template $BottlesNewBottleDialog: Adw.Dialog { +template $NewBottleDialog: Adw.Dialog { content-width: 500; content-height: 500; title: _("Create New Bottle"); diff --git a/bottles/frontend/views/new_bottle_dialog.py b/bottles/frontend/views/new_bottle_dialog.py index a8b007d4a1f..e5c259304d3 100644 --- a/bottles/frontend/views/new_bottle_dialog.py +++ b/bottles/frontend/views/new_bottle_dialog.py @@ -47,8 +47,8 @@ class BottlesCheckRow(Adw.ActionRow): @Gtk.Template(resource_path="/com/usebottles/bottles/new-bottle-dialog.ui") -class BottlesNewBottleDialog(Adw.Dialog): - __gtype_name__ = "BottlesNewBottleDialog" +class NewBottleDialog(Adw.Dialog): + __gtype_name__ = "NewBottleDialog" # region Widgets entry_name = Gtk.Template.Child() diff --git a/bottles/frontend/windows/window.py b/bottles/frontend/windows/window.py index bddd3f34253..ac24c55b695 100644 --- a/bottles/frontend/windows/window.py +++ b/bottles/frontend/windows/window.py @@ -41,7 +41,7 @@ from bottles.frontend.views.library import LibraryView from bottles.frontend.views.list import BottleView from bottles.frontend.views.loading import LoadingView -from bottles.frontend.views.new_bottle_dialog import BottlesNewBottleDialog +from bottles.frontend.views.new_bottle_dialog import NewBottleDialog from bottles.frontend.views.preferences import PreferencesWindow from bottles.frontend.windows.crash import CrashReportDialog from bottles.frontend.windows.depscheck import DependenciesCheckDialog @@ -328,7 +328,7 @@ def show_onboard_view(self, widget=False): onboard_window.present() def show_add_view(self, widget=False): - new_bottle_dialog = BottlesNewBottleDialog() + new_bottle_dialog = NewBottleDialog() new_bottle_dialog.present(self) def show_list_view(self, widget=False): diff --git a/po/POTFILES b/po/POTFILES index 6f9bca14ddc..0929ce8add4 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -46,7 +46,7 @@ bottles/frontend/ui/bottle-row.blp bottles/frontend/ui/list.blp bottles/frontend/ui/loading.blp bottles/frontend/ui/local-resource-entry.blp -bottles/frontend/ui/new.blp +bottles/frontend/ui/new-bottle-dialog.blp bottles/frontend/ui/onboard.blp bottles/frontend/ui/preferences.blp bottles/frontend/ui/program-entry.blp @@ -60,7 +60,7 @@ bottles/frontend/views/details.py bottles/frontend/views/importer.py bottles/frontend/views/list.py bottles/frontend/views/loading.py -bottles/frontend/views/new.py +bottles/frontend/views/new_bottle_dialog.py bottles/frontend/views/preferences.py bottles/frontend/widgets/component.py bottles/frontend/widgets/dependency.py From 870bdd94360219b39103c6c75c9342094045664c Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Sun, 12 Jan 2025 09:13:30 -0500 Subject: [PATCH 008/146] check-row: Rename to CheckRow --- bottles/frontend/ui/check-row.blp | 2 +- bottles/frontend/ui/new-bottle-dialog.blp | 6 +++--- bottles/frontend/views/new_bottle_dialog.py | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/bottles/frontend/ui/check-row.blp b/bottles/frontend/ui/check-row.blp index c4ce6d96efe..b4dda3bf3c6 100644 --- a/bottles/frontend/ui/check-row.blp +++ b/bottles/frontend/ui/check-row.blp @@ -1,7 +1,7 @@ using Gtk 4.0; using Adw 1; -template $BottlesCheckRow: Adw.ActionRow { +template $CheckRow: Adw.ActionRow { activatable-widget: check_button; active: bind check_button.active bidirectional; diff --git a/bottles/frontend/ui/new-bottle-dialog.blp b/bottles/frontend/ui/new-bottle-dialog.blp index 654edb6bc55..d13cc8e8949 100644 --- a/bottles/frontend/ui/new-bottle-dialog.blp +++ b/bottles/frontend/ui/new-bottle-dialog.blp @@ -67,7 +67,7 @@ template $NewBottleDialog: Adw.Dialog { "boxed-list", ] - $BottlesCheckRow application { + $CheckRow application { title: _("_Application"); environment: "application"; subtitle: _("Optimized for productivity software"); @@ -76,7 +76,7 @@ template $NewBottleDialog: Adw.Dialog { active: true; } - $BottlesCheckRow { + $CheckRow { title: _("_Gaming"); environment: "gaming"; subtitle: _("Optimized for games, game engines, and 3D apps"); @@ -85,7 +85,7 @@ template $NewBottleDialog: Adw.Dialog { group: application; } - $BottlesCheckRow custom { + $CheckRow custom { title: _("C_ustom"); environment: "custom"; subtitle: _("A clean state intended for specific use cases"); diff --git a/bottles/frontend/views/new_bottle_dialog.py b/bottles/frontend/views/new_bottle_dialog.py index e5c259304d3..82fafa2d260 100644 --- a/bottles/frontend/views/new_bottle_dialog.py +++ b/bottles/frontend/views/new_bottle_dialog.py @@ -27,10 +27,10 @@ @Gtk.Template(resource_path="/com/usebottles/bottles/check-row.ui") -class BottlesCheckRow(Adw.ActionRow): +class CheckRow(Adw.ActionRow): """An `AdwActionRow` with a designated `GtkCheckButton` as prefix.""" - __gtype_name__ = "BottlesCheckRow" + __gtype_name__ = "CheckRow" check_button = Gtk.Template.Child() @@ -39,7 +39,7 @@ class BottlesCheckRow(Adw.ActionRow): # Add row’s check button to the group group = GObject.Property( - # FIXME: Supposed to be a BottlesCheckRow widget type. + # FIXME: Supposed to be a CheckRow widget type. type=Adw.ActionRow, default=None, setter=lambda self, group: self.check_button.set_group(group.check_button), From f08dc052aafaa6751ffd48002933579d02de1674 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Sun, 12 Jan 2025 09:18:01 -0500 Subject: [PATCH 009/146] component-entry-row: Rename files and class name --- bottles/frontend/ui/bottles.gresource.xml | 2 +- ...{component-entry.blp => component-entry-row.blp} | 2 +- bottles/frontend/ui/meson.build | 2 +- bottles/frontend/views/preferences.py | 13 ++++++++----- .../{component.py => component_entry_row.py} | 10 +++++----- bottles/frontend/widgets/meson.build | 2 +- po/POTFILES | 2 +- 7 files changed, 18 insertions(+), 15 deletions(-) rename bottles/frontend/ui/{component-entry.blp => component-entry-row.blp} (96%) rename bottles/frontend/widgets/{component.py => component_entry_row.py} (97%) diff --git a/bottles/frontend/ui/bottles.gresource.xml b/bottles/frontend/ui/bottles.gresource.xml index 2e9eb7c9d32..acea4e6d369 100644 --- a/bottles/frontend/ui/bottles.gresource.xml +++ b/bottles/frontend/ui/bottles.gresource.xml @@ -18,7 +18,7 @@ installer-entry.ui dll-override-entry.ui env-var-entry.ui - component-entry.ui + component-entry-row.ui drive-entry.ui library-entry.ui local-resource-entry.ui diff --git a/bottles/frontend/ui/component-entry.blp b/bottles/frontend/ui/component-entry-row.blp similarity index 96% rename from bottles/frontend/ui/component-entry.blp rename to bottles/frontend/ui/component-entry-row.blp index 99236c4d66d..a01ced4c53a 100644 --- a/bottles/frontend/ui/component-entry.blp +++ b/bottles/frontend/ui/component-entry-row.blp @@ -1,7 +1,7 @@ using Gtk 4.0; using Adw 1; -template $ComponentEntry: Adw.ActionRow { +template $ComponentEntryRow: Adw.ActionRow { title: _("Component version"); Spinner spinner { diff --git a/bottles/frontend/ui/meson.build b/bottles/frontend/ui/meson.build index 6670427d10b..59bdd4028ef 100644 --- a/bottles/frontend/ui/meson.build +++ b/bottles/frontend/ui/meson.build @@ -2,7 +2,7 @@ pkgdatadir = join_paths(get_option('prefix'), get_option('datadir'), meson.proje gnome = import('gnome') blueprints = custom_target('blueprints', input: files( - 'component-entry.blp', + 'component-entry-row.blp', 'check-row.blp', 'dependency-entry.blp', 'details-bottle.blp', diff --git a/bottles/frontend/views/preferences.py b/bottles/frontend/views/preferences.py index 7ffb609ada9..aa214672cdf 100644 --- a/bottles/frontend/views/preferences.py +++ b/bottles/frontend/views/preferences.py @@ -26,7 +26,10 @@ from bottles.backend.state import EventManager, Events from bottles.backend.utils.threading import RunAsync from bottles.backend.utils.generic import sort_by_version -from bottles.frontend.widgets.component import ComponentEntry, ComponentExpander +from bottles.frontend.widgets.component_entry_row import ( + ComponentEntryRow, + ComponentExpander, +) @Gtk.Template(resource_path="/com/usebottles/bottles/preferences.ui") @@ -305,7 +308,7 @@ def __populate_component_list( for component in supported_component_items: if not self.__display_unstable_candidate(component): continue - _entry = ComponentEntry(self.window, component, component_type) + _entry = ComponentEntryRow(self.window, component, component_type) list_component.add(_entry) self.__registry.append(_entry) @@ -355,7 +358,7 @@ def __populate_runners_helper( if not self.__display_unstable_candidate(supported_runner): continue - _entry = ComponentEntry(self.window, supported_runner, runner_type) + _entry = ComponentEntryRow(self.window, supported_runner, runner_type) for identifiable_runner in identifiable_runners_struct: if _runner_name.startswith(identifiable_runner["prefix"]): while ( @@ -369,7 +372,7 @@ def __populate_runners_helper( == identifiable_runner["offline_runners"][0][0] ): offline_runner = identifiable_runner["offline_runners"].pop(0) - _offline_entry = ComponentEntry( + _offline_entry = ComponentEntryRow( self.window, offline_runner, runner_type ) identifiable_runner["expander"].add_row(_offline_entry) @@ -382,7 +385,7 @@ def __populate_runners_helper( for identifiable_runner in identifiable_runners_struct: while identifiable_runner["offline_runners"]: offline_runner = identifiable_runner["offline_runners"].pop(0) - _offline_entry = ComponentEntry( + _offline_entry = ComponentEntryRow( self.window, offline_runner, runner_type ) identifiable_runner["expander"].add_row(_offline_entry) diff --git a/bottles/frontend/widgets/component.py b/bottles/frontend/widgets/component_entry_row.py similarity index 97% rename from bottles/frontend/widgets/component.py rename to bottles/frontend/widgets/component_entry_row.py index 1bc32e510b0..5b7766b6a89 100644 --- a/bottles/frontend/widgets/component.py +++ b/bottles/frontend/widgets/component_entry_row.py @@ -1,6 +1,6 @@ -# component.py +# component_entry_row.py # -# Copyright 2022 brombinmirko +# Copyright 2025 The Bottles Contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -29,9 +29,9 @@ logging = Logger() -@Gtk.Template(resource_path="/com/usebottles/bottles/component-entry.ui") -class ComponentEntry(Adw.ActionRow): - __gtype_name__ = "ComponentEntry" +@Gtk.Template(resource_path="/com/usebottles/bottles/component-entry-row.ui") +class ComponentEntryRow(Adw.ActionRow): + __gtype_name__ = "ComponentEntryRow" __gsignals__ = { "component-installed": (GObject.SIGNAL_RUN_FIRST, None, ()), "component-error": (GObject.SIGNAL_RUN_FIRST, None, ()), diff --git a/bottles/frontend/widgets/meson.build b/bottles/frontend/widgets/meson.build index 184f6e13f65..a30dda83770 100644 --- a/bottles/frontend/widgets/meson.build +++ b/bottles/frontend/widgets/meson.build @@ -9,7 +9,7 @@ bottles_sources = [ 'installer.py', 'program.py', 'state.py', - 'component.py', + 'component_entry_row.py', 'library.py', ] diff --git a/po/POTFILES b/po/POTFILES index 0929ce8add4..89bf805f24b 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -6,7 +6,7 @@ bottles/backend/managers/versioning.py bottles/frontend/main.py bottles/frontend/operation.py bottles/frontend/ui/about.blp -bottles/frontend/ui/component-entry.blp +bottles/frontend/ui/component-entry-row.blp bottles/frontend/ui/dependency-entry.blp bottles/frontend/ui/details-bottle.blp bottles/frontend/ui/details-dependencies.blp From 458e293a61b328d3f49f85bf0d42badaeff9776f Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Sun, 12 Jan 2025 09:23:41 -0500 Subject: [PATCH 010/146] dependency-entry-row: Rename files and class name --- bottles/frontend/ui/bottles.gresource.xml | 2 +- .../{dependency-entry.blp => dependency-entry-row.blp} | 2 +- bottles/frontend/ui/meson.build | 2 +- bottles/frontend/views/bottle_dependencies.py | 4 ++-- .../widgets/{dependency.py => dependency_entry_row.py} | 10 +++++----- bottles/frontend/widgets/meson.build | 2 +- po/POTFILES | 2 +- 7 files changed, 12 insertions(+), 12 deletions(-) rename bottles/frontend/ui/{dependency-entry.blp => dependency-entry-row.blp} (97%) rename bottles/frontend/widgets/{dependency.py => dependency_entry_row.py} (97%) diff --git a/bottles/frontend/ui/bottles.gresource.xml b/bottles/frontend/ui/bottles.gresource.xml index acea4e6d369..6623c1543b0 100644 --- a/bottles/frontend/ui/bottles.gresource.xml +++ b/bottles/frontend/ui/bottles.gresource.xml @@ -11,7 +11,7 @@ bottle-row.ui check-row.ui task-entry.ui - dependency-entry.ui + dependency-entry-row.ui program-entry.ui importer-entry.ui state-entry.ui diff --git a/bottles/frontend/ui/dependency-entry.blp b/bottles/frontend/ui/dependency-entry-row.blp similarity index 97% rename from bottles/frontend/ui/dependency-entry.blp rename to bottles/frontend/ui/dependency-entry-row.blp index b7bbe5473f8..a2920677a49 100644 --- a/bottles/frontend/ui/dependency-entry.blp +++ b/bottles/frontend/ui/dependency-entry-row.blp @@ -38,7 +38,7 @@ Popover pop_actions { } } -template $DependencyEntry: Adw.ActionRow { +template $DependencyEntryRow: Adw.ActionRow { title: _("Dependency name"); activatable-widget: btn_install; subtitle: _("Dependency description"); diff --git a/bottles/frontend/ui/meson.build b/bottles/frontend/ui/meson.build index 59bdd4028ef..cb016489ff1 100644 --- a/bottles/frontend/ui/meson.build +++ b/bottles/frontend/ui/meson.build @@ -4,7 +4,7 @@ blueprints = custom_target('blueprints', input: files( 'component-entry-row.blp', 'check-row.blp', - 'dependency-entry.blp', + 'dependency-entry-row.blp', 'details-bottle.blp', 'details-dependencies.blp', 'details-installers.blp', diff --git a/bottles/frontend/views/bottle_dependencies.py b/bottles/frontend/views/bottle_dependencies.py index f96b3bf29d2..fb88732ffa7 100644 --- a/bottles/frontend/views/bottle_dependencies.py +++ b/bottles/frontend/views/bottle_dependencies.py @@ -25,7 +25,7 @@ from bottles.backend.utils.threading import RunAsync from bottles.frontend.utils.common import open_doc_url from bottles.frontend.utils.gtk import GtkUtils -from bottles.frontend.widgets.dependency import DependencyEntry +from bottles.frontend.widgets.dependency_entry_row import DependencyEntryRow @Gtk.Template(resource_path="/com/usebottles/bottles/details-dependencies.ui") @@ -107,7 +107,7 @@ def update(self, _widget=False, config: Optional[BottleConfig] = None): self.stack.set_visible_child_name("page_loading") def new_dependency(dependency, plain=False): - entry = DependencyEntry( + entry = DependencyEntryRow( window=self.window, config=self.config, dependency=dependency, diff --git a/bottles/frontend/widgets/dependency.py b/bottles/frontend/widgets/dependency_entry_row.py similarity index 97% rename from bottles/frontend/widgets/dependency.py rename to bottles/frontend/widgets/dependency_entry_row.py index 226e915a5e1..3595926c75b 100644 --- a/bottles/frontend/widgets/dependency.py +++ b/bottles/frontend/widgets/dependency_entry_row.py @@ -1,6 +1,6 @@ -# dependency.py +# dependency_entry_row.py # -# Copyright 2022 brombinmirko +# Copyright 2025 The Bottles Contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -28,9 +28,9 @@ from bottles.frontend.windows.generic import SourceDialog -@Gtk.Template(resource_path="/com/usebottles/bottles/dependency-entry.ui") -class DependencyEntry(Adw.ActionRow): - __gtype_name__ = "DependencyEntry" +@Gtk.Template(resource_path="/com/usebottles/bottles/dependency-entry-row.ui") +class DependencyEntryRow(Adw.ActionRow): + __gtype_name__ = "DependencyEntryRow" # region Widgets label_category = Gtk.Template.Child() diff --git a/bottles/frontend/widgets/meson.build b/bottles/frontend/widgets/meson.build index a30dda83770..b763a20fe2a 100644 --- a/bottles/frontend/widgets/meson.build +++ b/bottles/frontend/widgets/meson.build @@ -3,7 +3,7 @@ widgetsdir = join_paths(pkgdatadir, 'bottles/frontend/widgets') bottles_sources = [ '__init__.py', - 'dependency.py', + 'dependency_entry_row.py', 'executable.py', 'importer.py', 'installer.py', diff --git a/po/POTFILES b/po/POTFILES index 89bf805f24b..dfecc469c7f 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -7,7 +7,7 @@ bottles/frontend/main.py bottles/frontend/operation.py bottles/frontend/ui/about.blp bottles/frontend/ui/component-entry-row.blp -bottles/frontend/ui/dependency-entry.blp +bottles/frontend/ui/dependency-entry-row.blp bottles/frontend/ui/details-bottle.blp bottles/frontend/ui/details-dependencies.blp bottles/frontend/ui/details-installers.blp From ac5d0cba4ac412ddf21eafe920c980ccb6d6f384 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Sun, 12 Jan 2025 09:35:46 -0500 Subject: [PATCH 011/146] bottle-details-view: Rename files and class name --- .../ui/{details.blp => bottle-details-view.blp} | 2 +- bottles/frontend/ui/bottles.gresource.xml | 2 +- bottles/frontend/ui/meson.build | 2 +- .../views/{details.py => bottle_details_view.py} | 12 ++++++------ bottles/frontend/views/meson.build | 2 +- bottles/frontend/windows/window.py | 4 ++-- po/POTFILES | 4 ++-- 7 files changed, 14 insertions(+), 14 deletions(-) rename bottles/frontend/ui/{details.blp => bottle-details-view.blp} (97%) rename bottles/frontend/views/{details.py => bottle_details_view.py} (96%) diff --git a/bottles/frontend/ui/details.blp b/bottles/frontend/ui/bottle-details-view.blp similarity index 97% rename from bottles/frontend/ui/details.blp rename to bottles/frontend/ui/bottle-details-view.blp index 395efb77107..5c4797a0ad0 100644 --- a/bottles/frontend/ui/details.blp +++ b/bottles/frontend/ui/bottle-details-view.blp @@ -1,7 +1,7 @@ using Gtk 4.0; using Adw 1; -template $Details: Adw.Bin { +template $BottleDetailsView: Adw.Bin { Adw.Leaflet leaflet { can-navigate-back: true; can-unfold: false; diff --git a/bottles/frontend/ui/bottles.gresource.xml b/bottles/frontend/ui/bottles.gresource.xml index 6623c1543b0..4a11de35b31 100644 --- a/bottles/frontend/ui/bottles.gresource.xml +++ b/bottles/frontend/ui/bottles.gresource.xml @@ -23,7 +23,7 @@ library-entry.ui local-resource-entry.ui exclusion-pattern-entry.ui - details.ui + bottle-details-view.ui details-bottle.ui details-dependencies.ui details-installers.ui diff --git a/bottles/frontend/ui/meson.build b/bottles/frontend/ui/meson.build index cb016489ff1..9d06830919b 100644 --- a/bottles/frontend/ui/meson.build +++ b/bottles/frontend/ui/meson.build @@ -10,7 +10,7 @@ blueprints = custom_target('blueprints', 'details-installers.blp', 'details-taskmanager.blp', 'details-versioning.blp', - 'details.blp', + 'bottle-details-view.blp', 'dialog-bottle-picker.blp', 'dialog-crash-report.blp', 'dialog-deps-check.blp', diff --git a/bottles/frontend/views/details.py b/bottles/frontend/views/bottle_details_view.py similarity index 96% rename from bottles/frontend/views/details.py rename to bottles/frontend/views/bottle_details_view.py index b2bf6091c85..b5fc5d6129a 100644 --- a/bottles/frontend/views/details.py +++ b/bottles/frontend/views/bottle_details_view.py @@ -1,6 +1,6 @@ -# details.py +# bottle_details_view.py # -# Copyright 2022 brombinmirko +# Copyright 2025 The Bottles Contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -34,14 +34,14 @@ from bottles.frontend.views.bottle_taskmanager import TaskManagerView -@Gtk.Template(resource_path="/com/usebottles/bottles/details.ui") -class DetailsView(Adw.Bin): +@Gtk.Template(resource_path="/com/usebottles/bottles/bottle-details-view.ui") +class BottleDetailsView(Adw.Bin): """ This class is the starting point for all the pages concerning the bottle (details, preferences, dependencies ..). """ - __gtype_name__ = "Details" + __gtype_name__ = "BottleDetailsView" __pages = {} # region Widgets @@ -98,7 +98,7 @@ def __init__(self, window, config: Optional[BottleConfig] = None, **kwargs): def set_title(self, title, subtitle: str = ""): """ - This function is used to set the title of the DetailsView + This function is used to set the title of the BottleDetailsView headerbar. """ self.content_title.set_title(title) diff --git a/bottles/frontend/views/meson.build b/bottles/frontend/views/meson.build index bfadaffe0fa..e032322a0f2 100644 --- a/bottles/frontend/views/meson.build +++ b/bottles/frontend/views/meson.build @@ -6,7 +6,7 @@ bottles_sources = [ 'new_bottle_dialog.py', 'list.py', 'library.py', - 'details.py', + 'bottle_details_view.py', 'preferences.py', 'importer.py', 'loading.py', diff --git a/bottles/frontend/windows/window.py b/bottles/frontend/windows/window.py index ac24c55b695..3881853619e 100644 --- a/bottles/frontend/windows/window.py +++ b/bottles/frontend/windows/window.py @@ -36,7 +36,7 @@ from bottles.frontend.operation import TaskSyncer from bottles.frontend.params import APP_ID, BASE_ID, PROFILE from bottles.frontend.utils.gtk import GtkUtils -from bottles.frontend.views.details import DetailsView +from bottles.frontend.views.bottle_details_view import BottleDetailsView from bottles.frontend.views.importer import ImporterView from bottles.frontend.views.library import LibraryView from bottles.frontend.views.list import BottleView @@ -220,7 +220,7 @@ def set_manager(result: Manager, error=None): self.show_onboard_view() # Pages - self.page_details = DetailsView(self) + self.page_details = BottleDetailsView(self) self.page_list = BottleView(self, arg_bottle=self.arg_bottle) self.page_importer = ImporterView(self) self.page_library = LibraryView(self) diff --git a/po/POTFILES b/po/POTFILES index dfecc469c7f..bd680c9304d 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -14,7 +14,7 @@ bottles/frontend/ui/details-installers.blp bottles/frontend/ui/details-preferences.blp bottles/frontend/ui/details-taskmanager.blp bottles/frontend/ui/details-versioning.blp -bottles/frontend/ui/details.blp +bottles/frontend/ui/bottle-details-view.blp bottles/frontend/ui/dialog-bottle-picker.blp bottles/frontend/ui/dialog-crash-report.blp bottles/frontend/ui/dialog-deps-check.blp @@ -56,7 +56,7 @@ bottles/frontend/ui/window.blp bottles/frontend/views/bottle_details.py bottles/frontend/views/bottle_preferences.py bottles/frontend/views/bottle_versioning.py -bottles/frontend/views/details.py +bottles/frontend/views/bottle_details_view.py bottles/frontend/views/importer.py bottles/frontend/views/list.py bottles/frontend/views/loading.py From fb234ae55b11cfa80acf3f18ce11dabecbedea99 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Sun, 12 Jan 2025 09:46:46 -0500 Subject: [PATCH 012/146] bottle-details-page: Rename files and class name --- .../ui/{details-bottle.blp => bottle-details-page.blp} | 2 +- bottles/frontend/ui/bottles.gresource.xml | 2 +- bottles/frontend/ui/meson.build | 2 +- .../{bottle_details.py => bottle_details_page.py} | 10 +++++----- bottles/frontend/views/bottle_details_view.py | 4 ++-- bottles/frontend/views/meson.build | 2 +- po/POTFILES | 4 ++-- 7 files changed, 13 insertions(+), 13 deletions(-) rename bottles/frontend/ui/{details-bottle.blp => bottle-details-page.blp} (99%) rename bottles/frontend/views/{bottle_details.py => bottle_details_page.py} (99%) diff --git a/bottles/frontend/ui/details-bottle.blp b/bottles/frontend/ui/bottle-details-page.blp similarity index 99% rename from bottles/frontend/ui/details-bottle.blp rename to bottles/frontend/ui/bottle-details-page.blp index 3ad98f94fcd..670faec8798 100644 --- a/bottles/frontend/ui/details-bottle.blp +++ b/bottles/frontend/ui/bottle-details-page.blp @@ -140,7 +140,7 @@ Popover popover_exec_settings { } } -template $DetailsBottle: Adw.PreferencesPage { +template $BottleDetailsPage: Adw.PreferencesPage { Overlay drop_overlay { visible: false; diff --git a/bottles/frontend/ui/bottles.gresource.xml b/bottles/frontend/ui/bottles.gresource.xml index 4a11de35b31..d07b4ee3eb2 100644 --- a/bottles/frontend/ui/bottles.gresource.xml +++ b/bottles/frontend/ui/bottles.gresource.xml @@ -24,7 +24,7 @@ local-resource-entry.ui exclusion-pattern-entry.ui bottle-details-view.ui - details-bottle.ui + bottle-details-page.ui details-dependencies.ui details-installers.ui details-preferences.ui diff --git a/bottles/frontend/ui/meson.build b/bottles/frontend/ui/meson.build index 9d06830919b..310286eea39 100644 --- a/bottles/frontend/ui/meson.build +++ b/bottles/frontend/ui/meson.build @@ -5,7 +5,7 @@ blueprints = custom_target('blueprints', 'component-entry-row.blp', 'check-row.blp', 'dependency-entry-row.blp', - 'details-bottle.blp', + 'bottle-details-page.blp', 'details-dependencies.blp', 'details-installers.blp', 'details-taskmanager.blp', diff --git a/bottles/frontend/views/bottle_details.py b/bottles/frontend/views/bottle_details_page.py similarity index 99% rename from bottles/frontend/views/bottle_details.py rename to bottles/frontend/views/bottle_details_page.py index c7f49ae0d0c..57cd03a383b 100644 --- a/bottles/frontend/views/bottle_details.py +++ b/bottles/frontend/views/bottle_details_page.py @@ -1,6 +1,6 @@ -# bottle_details.py +# bottle_details_page.py # -# Copyright 2022 brombinmirko +# Copyright 2025 The Bottles Contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -46,9 +46,9 @@ from bottles.frontend.windows.upgradeversioning import UpgradeVersioningDialog -@Gtk.Template(resource_path="/com/usebottles/bottles/details-bottle.ui") -class BottleView(Adw.PreferencesPage): - __gtype_name__ = "DetailsBottle" +@Gtk.Template(resource_path="/com/usebottles/bottles/bottle-details-page.ui") +class BottleDetailsPage(Adw.PreferencesPage): + __gtype_name__ = "BottleDetailsPage" __registry = [] # region Widgets diff --git a/bottles/frontend/views/bottle_details_view.py b/bottles/frontend/views/bottle_details_view.py index b5fc5d6129a..7a795ce4135 100644 --- a/bottles/frontend/views/bottle_details_view.py +++ b/bottles/frontend/views/bottle_details_view.py @@ -26,7 +26,7 @@ from bottles.backend.utils.threading import RunAsync from bottles.frontend.utils.gtk import GtkUtils -from bottles.frontend.views.bottle_details import BottleView +from bottles.frontend.views.bottle_details_page import BottleDetailsPage from bottles.frontend.views.bottle_installers import InstallersView from bottles.frontend.views.bottle_dependencies import DependenciesView from bottles.frontend.views.bottle_preferences import PreferencesView @@ -75,7 +75,7 @@ def __init__(self, window, config: Optional[BottleConfig] = None, **kwargs): self.config = config self.queue = QueueManager(add_fn=self.lock_back, end_fn=self.unlock_back) - self.view_bottle = BottleView(self, config) + self.view_bottle = BottleDetailsPage(self, config) self.view_installers = InstallersView(self, config) self.view_dependencies = DependenciesView(self, config) self.view_preferences = PreferencesView(self, config) diff --git a/bottles/frontend/views/meson.build b/bottles/frontend/views/meson.build index e032322a0f2..5e113414f18 100644 --- a/bottles/frontend/views/meson.build +++ b/bottles/frontend/views/meson.build @@ -11,7 +11,7 @@ bottles_sources = [ 'importer.py', 'loading.py', - 'bottle_details.py', + 'bottle_details_page.py', 'bottle_installers.py', 'bottle_dependencies.py', 'bottle_preferences.py', diff --git a/po/POTFILES b/po/POTFILES index bd680c9304d..6d937f0e2aa 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -8,7 +8,7 @@ bottles/frontend/operation.py bottles/frontend/ui/about.blp bottles/frontend/ui/component-entry-row.blp bottles/frontend/ui/dependency-entry-row.blp -bottles/frontend/ui/details-bottle.blp +bottles/frontend/ui/bottle-details-page.blp bottles/frontend/ui/details-dependencies.blp bottles/frontend/ui/details-installers.blp bottles/frontend/ui/details-preferences.blp @@ -53,7 +53,7 @@ bottles/frontend/ui/program-entry.blp bottles/frontend/ui/state-entry.blp bottles/frontend/ui/task-entry.blp bottles/frontend/ui/window.blp -bottles/frontend/views/bottle_details.py +bottles/frontend/views/bottle_details_page.py bottles/frontend/views/bottle_preferences.py bottles/frontend/views/bottle_versioning.py bottles/frontend/views/bottle_details_view.py From 55ef374bef88d6073a781be25792d8caac76cf32 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Sun, 12 Jan 2025 09:55:07 -0500 Subject: [PATCH 013/146] details-preferences-page: Rename files and class name --- bottles/frontend/ui/bottles.gresource.xml | 2 +- ...ls-preferences.blp => details-preferences-page.blp} | 2 +- bottles/frontend/ui/meson.build | 2 +- bottles/frontend/views/bottle_details_view.py | 4 ++-- ...ttle_preferences.py => details_preferences_page.py} | 10 +++++----- bottles/frontend/views/meson.build | 2 +- po/POTFILES | 4 ++-- 7 files changed, 13 insertions(+), 13 deletions(-) rename bottles/frontend/ui/{details-preferences.blp => details-preferences-page.blp} (99%) rename bottles/frontend/views/{bottle_preferences.py => details_preferences_page.py} (99%) diff --git a/bottles/frontend/ui/bottles.gresource.xml b/bottles/frontend/ui/bottles.gresource.xml index d07b4ee3eb2..984ab42c92d 100644 --- a/bottles/frontend/ui/bottles.gresource.xml +++ b/bottles/frontend/ui/bottles.gresource.xml @@ -27,7 +27,7 @@ bottle-details-page.ui details-dependencies.ui details-installers.ui - details-preferences.ui + details-preferences-page.ui details-versioning.ui details-taskmanager.ui preferences.ui diff --git a/bottles/frontend/ui/details-preferences.blp b/bottles/frontend/ui/details-preferences-page.blp similarity index 99% rename from bottles/frontend/ui/details-preferences.blp rename to bottles/frontend/ui/details-preferences-page.blp index d92d861f57c..58db442ef24 100644 --- a/bottles/frontend/ui/details-preferences.blp +++ b/bottles/frontend/ui/details-preferences-page.blp @@ -1,7 +1,7 @@ using Gtk 4.0; using Adw 1; -template $DetailsPreferences: Adw.PreferencesPage { +template $DetailsPreferencesPage: Adw.PreferencesPage { Adw.PreferencesGroup group_details { Adw.EntryRow entry_name { title: _("Name"); diff --git a/bottles/frontend/ui/meson.build b/bottles/frontend/ui/meson.build index 310286eea39..0c3b8801b85 100644 --- a/bottles/frontend/ui/meson.build +++ b/bottles/frontend/ui/meson.build @@ -52,7 +52,7 @@ blueprints = custom_target('blueprints', 'state-entry.blp', 'task-entry.blp', 'window.blp', - 'details-preferences.blp', + 'details-preferences-page.blp', 'help-overlay.blp', ), output: '.', diff --git a/bottles/frontend/views/bottle_details_view.py b/bottles/frontend/views/bottle_details_view.py index 7a795ce4135..d88b8b2b5f3 100644 --- a/bottles/frontend/views/bottle_details_view.py +++ b/bottles/frontend/views/bottle_details_view.py @@ -29,7 +29,7 @@ from bottles.frontend.views.bottle_details_page import BottleDetailsPage from bottles.frontend.views.bottle_installers import InstallersView from bottles.frontend.views.bottle_dependencies import DependenciesView -from bottles.frontend.views.bottle_preferences import PreferencesView +from bottles.frontend.views.details_preferences_page import DetailsPreferencesPage from bottles.frontend.views.bottle_versioning import VersioningView from bottles.frontend.views.bottle_taskmanager import TaskManagerView @@ -78,7 +78,7 @@ def __init__(self, window, config: Optional[BottleConfig] = None, **kwargs): self.view_bottle = BottleDetailsPage(self, config) self.view_installers = InstallersView(self, config) self.view_dependencies = DependenciesView(self, config) - self.view_preferences = PreferencesView(self, config) + self.view_preferences = DetailsPreferencesPage(self, config) self.view_versioning = VersioningView(self, config) self.view_taskmanager = TaskManagerView(self, config) diff --git a/bottles/frontend/views/bottle_preferences.py b/bottles/frontend/views/details_preferences_page.py similarity index 99% rename from bottles/frontend/views/bottle_preferences.py rename to bottles/frontend/views/details_preferences_page.py index 754576baed7..77a65cc4395 100644 --- a/bottles/frontend/views/bottle_preferences.py +++ b/bottles/frontend/views/details_preferences_page.py @@ -1,6 +1,6 @@ -# bottle_preferences.py +# details_preferences_page.py # -# Copyright 2022 brombinmirko +# Copyright 2025 The Bottles Contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -60,9 +60,9 @@ # noinspection PyUnusedLocal -@Gtk.Template(resource_path="/com/usebottles/bottles/details-preferences.ui") -class PreferencesView(Adw.PreferencesPage): - __gtype_name__ = "DetailsPreferences" +@Gtk.Template(resource_path="/com/usebottles/bottles/details-preferences-page.ui") +class DetailsPreferencesPage(Adw.PreferencesPage): + __gtype_name__ = "DetailsPreferencesPage" # region Widgets btn_manage_gamescope = Gtk.Template.Child() diff --git a/bottles/frontend/views/meson.build b/bottles/frontend/views/meson.build index 5e113414f18..b1b5e8b99c3 100644 --- a/bottles/frontend/views/meson.build +++ b/bottles/frontend/views/meson.build @@ -14,7 +14,7 @@ bottles_sources = [ 'bottle_details_page.py', 'bottle_installers.py', 'bottle_dependencies.py', - 'bottle_preferences.py', + 'details_preferences_page.py', 'bottle_versioning.py', 'bottle_taskmanager.py' ] diff --git a/po/POTFILES b/po/POTFILES index 6d937f0e2aa..3ef7c17b5fe 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -11,7 +11,7 @@ bottles/frontend/ui/dependency-entry-row.blp bottles/frontend/ui/bottle-details-page.blp bottles/frontend/ui/details-dependencies.blp bottles/frontend/ui/details-installers.blp -bottles/frontend/ui/details-preferences.blp +bottles/frontend/ui/details-preferences-page.blp bottles/frontend/ui/details-taskmanager.blp bottles/frontend/ui/details-versioning.blp bottles/frontend/ui/bottle-details-view.blp @@ -54,7 +54,7 @@ bottles/frontend/ui/state-entry.blp bottles/frontend/ui/task-entry.blp bottles/frontend/ui/window.blp bottles/frontend/views/bottle_details_page.py -bottles/frontend/views/bottle_preferences.py +bottles/frontend/views/details_preferences_page.py bottles/frontend/views/bottle_versioning.py bottles/frontend/views/bottle_details_view.py bottles/frontend/views/importer.py From 10fc8bb4dcabee747aee8554ef5d1bc35ad87efa Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Sun, 12 Jan 2025 14:53:23 -0500 Subject: [PATCH 014/146] details-task-manager-view: Rename files and class name --- bottles/frontend/ui/bottles.gresource.xml | 2 +- ...s-taskmanager.blp => details-task-manager-view.blp} | 2 +- bottles/frontend/ui/meson.build | 2 +- bottles/frontend/views/bottle_details_view.py | 4 ++-- ...tle_taskmanager.py => details_task_manager_view.py} | 10 +++++----- bottles/frontend/views/meson.build | 2 +- po/POTFILES | 2 +- 7 files changed, 12 insertions(+), 12 deletions(-) rename bottles/frontend/ui/{details-taskmanager.blp => details-task-manager-view.blp} (88%) rename bottles/frontend/views/{bottle_taskmanager.py => details_task_manager_view.py} (96%) diff --git a/bottles/frontend/ui/bottles.gresource.xml b/bottles/frontend/ui/bottles.gresource.xml index 984ab42c92d..2ce0639f324 100644 --- a/bottles/frontend/ui/bottles.gresource.xml +++ b/bottles/frontend/ui/bottles.gresource.xml @@ -29,7 +29,7 @@ details-installers.ui details-preferences-page.ui details-versioning.ui - details-taskmanager.ui + details-task-manager-view.ui preferences.ui importer.ui library.ui diff --git a/bottles/frontend/ui/details-taskmanager.blp b/bottles/frontend/ui/details-task-manager-view.blp similarity index 88% rename from bottles/frontend/ui/details-taskmanager.blp rename to bottles/frontend/ui/details-task-manager-view.blp index ec78ea5649d..ffe6f192dca 100644 --- a/bottles/frontend/ui/details-taskmanager.blp +++ b/bottles/frontend/ui/details-task-manager-view.blp @@ -1,6 +1,6 @@ using Gtk 4.0; -template $TaskManagerView: ScrolledWindow { +template $DetailsTaskManagerView: ScrolledWindow { TreeView treeview_processes { enable-grid-lines: horizontal; diff --git a/bottles/frontend/ui/meson.build b/bottles/frontend/ui/meson.build index 0c3b8801b85..4fddb0b19b4 100644 --- a/bottles/frontend/ui/meson.build +++ b/bottles/frontend/ui/meson.build @@ -8,7 +8,7 @@ blueprints = custom_target('blueprints', 'bottle-details-page.blp', 'details-dependencies.blp', 'details-installers.blp', - 'details-taskmanager.blp', + 'details-task-manager-view.blp', 'details-versioning.blp', 'bottle-details-view.blp', 'dialog-bottle-picker.blp', diff --git a/bottles/frontend/views/bottle_details_view.py b/bottles/frontend/views/bottle_details_view.py index d88b8b2b5f3..85a14b1b19c 100644 --- a/bottles/frontend/views/bottle_details_view.py +++ b/bottles/frontend/views/bottle_details_view.py @@ -31,7 +31,7 @@ from bottles.frontend.views.bottle_dependencies import DependenciesView from bottles.frontend.views.details_preferences_page import DetailsPreferencesPage from bottles.frontend.views.bottle_versioning import VersioningView -from bottles.frontend.views.bottle_taskmanager import TaskManagerView +from bottles.frontend.views.details_task_manager_view import DetailsTaskManagerView @Gtk.Template(resource_path="/com/usebottles/bottles/bottle-details-view.ui") @@ -80,7 +80,7 @@ def __init__(self, window, config: Optional[BottleConfig] = None, **kwargs): self.view_dependencies = DependenciesView(self, config) self.view_preferences = DetailsPreferencesPage(self, config) self.view_versioning = VersioningView(self, config) - self.view_taskmanager = TaskManagerView(self, config) + self.view_taskmanager = DetailsTaskManagerView(self, config) self.btn_back.connect("clicked", self.go_back) self.btn_back_sidebar.connect("clicked", self.go_back_sidebar) diff --git a/bottles/frontend/views/bottle_taskmanager.py b/bottles/frontend/views/details_task_manager_view.py similarity index 96% rename from bottles/frontend/views/bottle_taskmanager.py rename to bottles/frontend/views/details_task_manager_view.py index 012ab11c6ba..f2d6d25a7b9 100644 --- a/bottles/frontend/views/bottle_taskmanager.py +++ b/bottles/frontend/views/details_task_manager_view.py @@ -1,6 +1,6 @@ -# taskmanager.py +# details_task_manager_view.py # -# Copyright 2022 brombinmirko +# Copyright 2025 The Bottles Contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -26,9 +26,9 @@ from bottles.frontend.utils.gtk import GtkUtils -@Gtk.Template(resource_path="/com/usebottles/bottles/details-taskmanager.ui") -class TaskManagerView(Gtk.ScrolledWindow): - __gtype_name__ = "TaskManagerView" +@Gtk.Template(resource_path="/com/usebottles/bottles/details-task-manager-view.ui") +class DetailsTaskManagerView(Gtk.ScrolledWindow): + __gtype_name__ = "DetailsTaskManagerView" # region Widgets treeview_processes = Gtk.Template.Child() diff --git a/bottles/frontend/views/meson.build b/bottles/frontend/views/meson.build index b1b5e8b99c3..929e8ceecf5 100644 --- a/bottles/frontend/views/meson.build +++ b/bottles/frontend/views/meson.build @@ -16,7 +16,7 @@ bottles_sources = [ 'bottle_dependencies.py', 'details_preferences_page.py', 'bottle_versioning.py', - 'bottle_taskmanager.py' + 'details_task_manager_view.py' ] install_data(bottles_sources, install_dir: viewsdir) diff --git a/po/POTFILES b/po/POTFILES index 3ef7c17b5fe..5ed57b803e7 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -12,7 +12,7 @@ bottles/frontend/ui/bottle-details-page.blp bottles/frontend/ui/details-dependencies.blp bottles/frontend/ui/details-installers.blp bottles/frontend/ui/details-preferences-page.blp -bottles/frontend/ui/details-taskmanager.blp +bottles/frontend/ui/details-task-manager-view.blp bottles/frontend/ui/details-versioning.blp bottles/frontend/ui/bottle-details-view.blp bottles/frontend/ui/dialog-bottle-picker.blp From 2014a9839705de8e34ab9753089942521e0392b0 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Sun, 12 Jan 2025 14:57:34 -0500 Subject: [PATCH 015/146] details-versioning-page: Rename files and class name --- bottles/frontend/ui/bottles.gresource.xml | 2 +- ...ails-versioning.blp => details-versioning-page.blp} | 2 +- bottles/frontend/ui/meson.build | 2 +- bottles/frontend/views/bottle_details_view.py | 4 ++-- ...bottle_versioning.py => details_versioning_page.py} | 10 +++++----- bottles/frontend/views/meson.build | 2 +- po/POTFILES | 4 ++-- 7 files changed, 13 insertions(+), 13 deletions(-) rename bottles/frontend/ui/{details-versioning.blp => details-versioning-page.blp} (96%) rename bottles/frontend/views/{bottle_versioning.py => details_versioning_page.py} (96%) diff --git a/bottles/frontend/ui/bottles.gresource.xml b/bottles/frontend/ui/bottles.gresource.xml index 2ce0639f324..a15b956ad3f 100644 --- a/bottles/frontend/ui/bottles.gresource.xml +++ b/bottles/frontend/ui/bottles.gresource.xml @@ -28,7 +28,7 @@ details-dependencies.ui details-installers.ui details-preferences-page.ui - details-versioning.ui + details-versioning-page.ui details-task-manager-view.ui preferences.ui importer.ui diff --git a/bottles/frontend/ui/details-versioning.blp b/bottles/frontend/ui/details-versioning-page.blp similarity index 96% rename from bottles/frontend/ui/details-versioning.blp rename to bottles/frontend/ui/details-versioning-page.blp index 11458e8e962..99bc65a74bf 100644 --- a/bottles/frontend/ui/details-versioning.blp +++ b/bottles/frontend/ui/details-versioning-page.blp @@ -1,7 +1,7 @@ using Gtk 4.0; using Adw 1; -template $DetailsVersioning: Adw.PreferencesPage { +template $DetailsVersioningPage: Adw.PreferencesPage { Adw.PreferencesPage pref_page { Adw.PreferencesGroup { ListBox list_states { diff --git a/bottles/frontend/ui/meson.build b/bottles/frontend/ui/meson.build index 4fddb0b19b4..ebf643b64cf 100644 --- a/bottles/frontend/ui/meson.build +++ b/bottles/frontend/ui/meson.build @@ -9,7 +9,7 @@ blueprints = custom_target('blueprints', 'details-dependencies.blp', 'details-installers.blp', 'details-task-manager-view.blp', - 'details-versioning.blp', + 'details-versioning-page.blp', 'bottle-details-view.blp', 'dialog-bottle-picker.blp', 'dialog-crash-report.blp', diff --git a/bottles/frontend/views/bottle_details_view.py b/bottles/frontend/views/bottle_details_view.py index 85a14b1b19c..6d448c8b5c7 100644 --- a/bottles/frontend/views/bottle_details_view.py +++ b/bottles/frontend/views/bottle_details_view.py @@ -30,7 +30,7 @@ from bottles.frontend.views.bottle_installers import InstallersView from bottles.frontend.views.bottle_dependencies import DependenciesView from bottles.frontend.views.details_preferences_page import DetailsPreferencesPage -from bottles.frontend.views.bottle_versioning import VersioningView +from bottles.frontend.views.details_versioning_page import DetailsVersioningPage from bottles.frontend.views.details_task_manager_view import DetailsTaskManagerView @@ -79,7 +79,7 @@ def __init__(self, window, config: Optional[BottleConfig] = None, **kwargs): self.view_installers = InstallersView(self, config) self.view_dependencies = DependenciesView(self, config) self.view_preferences = DetailsPreferencesPage(self, config) - self.view_versioning = VersioningView(self, config) + self.view_versioning = DetailsVersioningPage(self, config) self.view_taskmanager = DetailsTaskManagerView(self, config) self.btn_back.connect("clicked", self.go_back) diff --git a/bottles/frontend/views/bottle_versioning.py b/bottles/frontend/views/details_versioning_page.py similarity index 96% rename from bottles/frontend/views/bottle_versioning.py rename to bottles/frontend/views/details_versioning_page.py index 4c2539a1760..946a6206843 100644 --- a/bottles/frontend/views/bottle_versioning.py +++ b/bottles/frontend/views/details_versioning_page.py @@ -1,6 +1,6 @@ -# bottle_versioning.py +# details_versioning_page.py # -# Copyright 2022 brombinmirko +# Copyright 2025 The Bottles Contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -27,9 +27,9 @@ from bottles.frontend.widgets.state import StateEntry -@Gtk.Template(resource_path="/com/usebottles/bottles/details-versioning.ui") -class VersioningView(Adw.PreferencesPage): - __gtype_name__ = "DetailsVersioning" +@Gtk.Template(resource_path="/com/usebottles/bottles/details-versioning-page.ui") +class DetailsVersioningPage(Adw.PreferencesPage): + __gtype_name__ = "DetailsVersioningPage" __registry = [] # region Widgets diff --git a/bottles/frontend/views/meson.build b/bottles/frontend/views/meson.build index 929e8ceecf5..403cddf5d0b 100644 --- a/bottles/frontend/views/meson.build +++ b/bottles/frontend/views/meson.build @@ -15,7 +15,7 @@ bottles_sources = [ 'bottle_installers.py', 'bottle_dependencies.py', 'details_preferences_page.py', - 'bottle_versioning.py', + 'details_versioning_page.py', 'details_task_manager_view.py' ] diff --git a/po/POTFILES b/po/POTFILES index 5ed57b803e7..e016da14d67 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -13,7 +13,7 @@ bottles/frontend/ui/details-dependencies.blp bottles/frontend/ui/details-installers.blp bottles/frontend/ui/details-preferences-page.blp bottles/frontend/ui/details-task-manager-view.blp -bottles/frontend/ui/details-versioning.blp +bottles/frontend/ui/details-versioning-page.blp bottles/frontend/ui/bottle-details-view.blp bottles/frontend/ui/dialog-bottle-picker.blp bottles/frontend/ui/dialog-crash-report.blp @@ -55,7 +55,7 @@ bottles/frontend/ui/task-entry.blp bottles/frontend/ui/window.blp bottles/frontend/views/bottle_details_page.py bottles/frontend/views/details_preferences_page.py -bottles/frontend/views/bottle_versioning.py +bottles/frontend/views/details_versioning_page.py bottles/frontend/views/bottle_details_view.py bottles/frontend/views/importer.py bottles/frontend/views/list.py From 98534f3c6adaa2e74fa15732b859bfbcbbf3c5a7 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Sun, 12 Jan 2025 15:00:30 -0500 Subject: [PATCH 016/146] bottle-picker-dialog: Rename files --- bottles/frontend/main.py | 2 +- .../{dialog-bottle-picker.blp => bottle-picker-dialog.blp} | 0 bottles/frontend/ui/bottles.gresource.xml | 2 +- bottles/frontend/ui/meson.build | 2 +- .../windows/{bottlepicker.py => bottle_picker_dialog.py} | 6 +++--- bottles/frontend/windows/meson.build | 2 +- po/POTFILES | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) rename bottles/frontend/ui/{dialog-bottle-picker.blp => bottle-picker-dialog.blp} (100%) rename bottles/frontend/windows/{bottlepicker.py => bottle_picker_dialog.py} (94%) diff --git a/bottles/frontend/main.py b/bottles/frontend/main.py index f6a07b15247..e5019150ab4 100644 --- a/bottles/frontend/main.py +++ b/bottles/frontend/main.py @@ -222,7 +222,7 @@ def __process_uri(self, uri): return 0 try: - from bottles.frontend.windows.bottlepicker import BottlePickerDialog + from bottles.frontend.windows.bottle_picker_dialog import BottlePickerDialog dialog = BottlePickerDialog(application=self, arg_exe=uri) dialog.present() diff --git a/bottles/frontend/ui/dialog-bottle-picker.blp b/bottles/frontend/ui/bottle-picker-dialog.blp similarity index 100% rename from bottles/frontend/ui/dialog-bottle-picker.blp rename to bottles/frontend/ui/bottle-picker-dialog.blp diff --git a/bottles/frontend/ui/bottles.gresource.xml b/bottles/frontend/ui/bottles.gresource.xml index a15b956ad3f..9e77f6bbc31 100644 --- a/bottles/frontend/ui/bottles.gresource.xml +++ b/bottles/frontend/ui/bottles.gresource.xml @@ -48,7 +48,7 @@ dialog-journal.ui dialog-sandbox.ui dialog-installer.ui - dialog-bottle-picker.ui + bottle-picker-dialog.ui dialog-proton-alert.ui dialog-deps-check.ui dialog-exclusion-patterns.ui diff --git a/bottles/frontend/ui/meson.build b/bottles/frontend/ui/meson.build index ebf643b64cf..4c019deddff 100644 --- a/bottles/frontend/ui/meson.build +++ b/bottles/frontend/ui/meson.build @@ -11,7 +11,7 @@ blueprints = custom_target('blueprints', 'details-task-manager-view.blp', 'details-versioning-page.blp', 'bottle-details-view.blp', - 'dialog-bottle-picker.blp', + 'bottle-picker-dialog.blp', 'dialog-crash-report.blp', 'dialog-deps-check.blp', 'dialog-dll-overrides.blp', diff --git a/bottles/frontend/windows/bottlepicker.py b/bottles/frontend/windows/bottle_picker_dialog.py similarity index 94% rename from bottles/frontend/windows/bottlepicker.py rename to bottles/frontend/windows/bottle_picker_dialog.py index 89047f74fa7..9332fc9327a 100644 --- a/bottles/frontend/windows/bottlepicker.py +++ b/bottles/frontend/windows/bottle_picker_dialog.py @@ -1,6 +1,6 @@ -# bottlepicker.py +# bottle_picker_dialog.py # -# Copyright 2022 brombinmirko +# Copyright 2025 The Bottles Contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -31,7 +31,7 @@ def __init__(self, config: BottleConfig): self.set_title(config.Name) -@Gtk.Template(resource_path="/com/usebottles/bottles/dialog-bottle-picker.ui") +@Gtk.Template(resource_path="/com/usebottles/bottles/bottle-picker-dialog.ui") class BottlePickerDialog(Adw.ApplicationWindow): """This class should not be called from the application GUI, only from CLI.""" diff --git a/bottles/frontend/windows/meson.build b/bottles/frontend/windows/meson.build index ab7578824ed..a9b33f6d13a 100644 --- a/bottles/frontend/windows/meson.build +++ b/bottles/frontend/windows/meson.build @@ -19,7 +19,7 @@ bottles_sources = [ 'display.py', 'generic_cli.py', 'journal.py', - 'bottlepicker.py', + 'bottle_picker_dialog.py', 'protonalert.py', 'sandbox.py', 'installer.py', diff --git a/po/POTFILES b/po/POTFILES index e016da14d67..fee52b6b7a8 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -15,7 +15,7 @@ bottles/frontend/ui/details-preferences-page.blp bottles/frontend/ui/details-task-manager-view.blp bottles/frontend/ui/details-versioning-page.blp bottles/frontend/ui/bottle-details-view.blp -bottles/frontend/ui/dialog-bottle-picker.blp +bottles/frontend/ui/bottle-picker-dialog.blp bottles/frontend/ui/dialog-crash-report.blp bottles/frontend/ui/dialog-deps-check.blp bottles/frontend/ui/dialog-dll-overrides.blp From 65f73500f4bee6176307ae6fc44e32ac8c502062 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Sun, 12 Jan 2025 15:04:05 -0500 Subject: [PATCH 017/146] crash-report-dialog: Rename files --- bottles/frontend/ui/bottles.gresource.xml | 2 +- .../ui/{dialog-crash-report.blp => crash-report-dialog.blp} | 0 bottles/frontend/ui/meson.build | 2 +- .../frontend/windows/{crash.py => crash_report_dialog.py} | 6 +++--- bottles/frontend/windows/meson.build | 2 +- bottles/frontend/windows/window.py | 2 +- po/POTFILES | 4 ++-- 7 files changed, 9 insertions(+), 9 deletions(-) rename bottles/frontend/ui/{dialog-crash-report.blp => crash-report-dialog.blp} (100%) rename bottles/frontend/windows/{crash.py => crash_report_dialog.py} (97%) diff --git a/bottles/frontend/ui/bottles.gresource.xml b/bottles/frontend/ui/bottles.gresource.xml index 9e77f6bbc31..33b0f72c6d4 100644 --- a/bottles/frontend/ui/bottles.gresource.xml +++ b/bottles/frontend/ui/bottles.gresource.xml @@ -36,7 +36,7 @@ dialog-launch-options.ui dialog-dll-overrides.ui dialog-env-vars.ui - dialog-crash-report.ui + crash-report-dialog.ui dialog-duplicate.ui dialog-rename.ui dialog-gamescope.ui diff --git a/bottles/frontend/ui/dialog-crash-report.blp b/bottles/frontend/ui/crash-report-dialog.blp similarity index 100% rename from bottles/frontend/ui/dialog-crash-report.blp rename to bottles/frontend/ui/crash-report-dialog.blp diff --git a/bottles/frontend/ui/meson.build b/bottles/frontend/ui/meson.build index 4c019deddff..2c641ad4a3a 100644 --- a/bottles/frontend/ui/meson.build +++ b/bottles/frontend/ui/meson.build @@ -12,7 +12,7 @@ blueprints = custom_target('blueprints', 'details-versioning-page.blp', 'bottle-details-view.blp', 'bottle-picker-dialog.blp', - 'dialog-crash-report.blp', + 'crash-report-dialog.blp', 'dialog-deps-check.blp', 'dialog-dll-overrides.blp', 'dialog-drives.blp', diff --git a/bottles/frontend/windows/crash.py b/bottles/frontend/windows/crash_report_dialog.py similarity index 97% rename from bottles/frontend/windows/crash.py rename to bottles/frontend/windows/crash_report_dialog.py index 351f0f3d1bc..f7cfc7ea29e 100644 --- a/bottles/frontend/windows/crash.py +++ b/bottles/frontend/windows/crash_report_dialog.py @@ -1,6 +1,6 @@ -# crash.py +# crash_report_dialog.py # -# Copyright 2022 brombinmirko +# Copyright 2025 The Bottles Contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -45,7 +45,7 @@ def __on_btn_report_clicked(button, report): webbrowser.open(report["html_url"]) -@Gtk.Template(resource_path="/com/usebottles/bottles/dialog-crash-report.ui") +@Gtk.Template(resource_path="/com/usebottles/bottles/crash-report-dialog.ui") class CrashReportDialog(Adw.Window): __gtype_name__ = "CrashReportDialog" diff --git a/bottles/frontend/windows/meson.build b/bottles/frontend/windows/meson.build index a9b33f6d13a..34635aeb3bf 100644 --- a/bottles/frontend/windows/meson.build +++ b/bottles/frontend/windows/meson.build @@ -3,7 +3,7 @@ dialogsdir = join_paths(pkgdatadir, 'bottles/frontend/windows') bottles_sources = [ '__init__.py', - 'crash.py', + 'crash_report_dialog.py', 'dlloverrides.py', 'duplicate.py', 'envvars.py', diff --git a/bottles/frontend/windows/window.py b/bottles/frontend/windows/window.py index 3881853619e..aa43bb0733a 100644 --- a/bottles/frontend/windows/window.py +++ b/bottles/frontend/windows/window.py @@ -43,7 +43,7 @@ from bottles.frontend.views.loading import LoadingView from bottles.frontend.views.new_bottle_dialog import NewBottleDialog from bottles.frontend.views.preferences import PreferencesWindow -from bottles.frontend.windows.crash import CrashReportDialog +from bottles.frontend.windows.crash_report_dialog import CrashReportDialog from bottles.frontend.windows.depscheck import DependenciesCheckDialog from bottles.frontend.windows.onboard import OnboardDialog diff --git a/po/POTFILES b/po/POTFILES index fee52b6b7a8..cbb83d78be1 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -16,7 +16,7 @@ bottles/frontend/ui/details-task-manager-view.blp bottles/frontend/ui/details-versioning-page.blp bottles/frontend/ui/bottle-details-view.blp bottles/frontend/ui/bottle-picker-dialog.blp -bottles/frontend/ui/dialog-crash-report.blp +bottles/frontend/ui/crash-report-dialog.blp bottles/frontend/ui/dialog-deps-check.blp bottles/frontend/ui/dialog-dll-overrides.blp bottles/frontend/ui/dialog-drives.blp @@ -69,7 +69,7 @@ bottles/frontend/widgets/installer.py bottles/frontend/widgets/library.py bottles/frontend/widgets/program.py bottles/frontend/widgets/state.py -bottles/frontend/windows/crash.py +bottles/frontend/windows/crash_report_dialog.py bottles/frontend/windows/display.py bottles/frontend/windows/dlloverrides.py bottles/frontend/windows/drives.py From b88a4fc339f086944ad17cd2406d590e9a60636c Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Sun, 12 Jan 2025 15:15:02 -0500 Subject: [PATCH 018/146] details-dependencies-view: Rename files and class name --- bottles/frontend/ui/bottles.gresource.xml | 2 +- ...-dependencies.blp => details-dependencies-view.blp} | 2 +- bottles/frontend/ui/meson.build | 2 +- bottles/frontend/views/bottle_details_view.py | 4 ++-- ...le_dependencies.py => details_dependencies_view.py} | 10 +++++----- bottles/frontend/views/meson.build | 2 +- po/POTFILES | 2 +- 7 files changed, 12 insertions(+), 12 deletions(-) rename bottles/frontend/ui/{details-dependencies.blp => details-dependencies-view.blp} (97%) rename bottles/frontend/views/{bottle_dependencies.py => details_dependencies_view.py} (96%) diff --git a/bottles/frontend/ui/bottles.gresource.xml b/bottles/frontend/ui/bottles.gresource.xml index 33b0f72c6d4..d7bdfcfebd0 100644 --- a/bottles/frontend/ui/bottles.gresource.xml +++ b/bottles/frontend/ui/bottles.gresource.xml @@ -25,7 +25,7 @@ exclusion-pattern-entry.ui bottle-details-view.ui bottle-details-page.ui - details-dependencies.ui + details-dependencies-view.ui details-installers.ui details-preferences-page.ui details-versioning-page.ui diff --git a/bottles/frontend/ui/details-dependencies.blp b/bottles/frontend/ui/details-dependencies-view.blp similarity index 97% rename from bottles/frontend/ui/details-dependencies.blp rename to bottles/frontend/ui/details-dependencies-view.blp index 7565f545d4e..6524212f1a5 100644 --- a/bottles/frontend/ui/details-dependencies.blp +++ b/bottles/frontend/ui/details-dependencies-view.blp @@ -1,7 +1,7 @@ using Gtk 4.0; using Adw 1; -template $DetailsDependencies: Adw.Bin { +template $DetailsDependenciesView: Adw.Bin { Box { orientation: vertical; diff --git a/bottles/frontend/ui/meson.build b/bottles/frontend/ui/meson.build index 2c641ad4a3a..ea27c696210 100644 --- a/bottles/frontend/ui/meson.build +++ b/bottles/frontend/ui/meson.build @@ -6,7 +6,7 @@ blueprints = custom_target('blueprints', 'check-row.blp', 'dependency-entry-row.blp', 'bottle-details-page.blp', - 'details-dependencies.blp', + 'details-dependencies-view.blp', 'details-installers.blp', 'details-task-manager-view.blp', 'details-versioning-page.blp', diff --git a/bottles/frontend/views/bottle_details_view.py b/bottles/frontend/views/bottle_details_view.py index 6d448c8b5c7..f55fa51378b 100644 --- a/bottles/frontend/views/bottle_details_view.py +++ b/bottles/frontend/views/bottle_details_view.py @@ -28,7 +28,7 @@ from bottles.frontend.utils.gtk import GtkUtils from bottles.frontend.views.bottle_details_page import BottleDetailsPage from bottles.frontend.views.bottle_installers import InstallersView -from bottles.frontend.views.bottle_dependencies import DependenciesView +from bottles.frontend.views.details_dependencies_view import DetailsDependenciesView from bottles.frontend.views.details_preferences_page import DetailsPreferencesPage from bottles.frontend.views.details_versioning_page import DetailsVersioningPage from bottles.frontend.views.details_task_manager_view import DetailsTaskManagerView @@ -77,7 +77,7 @@ def __init__(self, window, config: Optional[BottleConfig] = None, **kwargs): self.view_bottle = BottleDetailsPage(self, config) self.view_installers = InstallersView(self, config) - self.view_dependencies = DependenciesView(self, config) + self.view_dependencies = DetailsDependenciesView(self, config) self.view_preferences = DetailsPreferencesPage(self, config) self.view_versioning = DetailsVersioningPage(self, config) self.view_taskmanager = DetailsTaskManagerView(self, config) diff --git a/bottles/frontend/views/bottle_dependencies.py b/bottles/frontend/views/details_dependencies_view.py similarity index 96% rename from bottles/frontend/views/bottle_dependencies.py rename to bottles/frontend/views/details_dependencies_view.py index fb88732ffa7..e93bcea5c83 100644 --- a/bottles/frontend/views/bottle_dependencies.py +++ b/bottles/frontend/views/details_dependencies_view.py @@ -1,6 +1,6 @@ -# bottle_installers.py +# details_dependencies_view.py # -# Copyright 2022 brombinmirko +# Copyright 2025 The Bottles Contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -28,9 +28,9 @@ from bottles.frontend.widgets.dependency_entry_row import DependencyEntryRow -@Gtk.Template(resource_path="/com/usebottles/bottles/details-dependencies.ui") -class DependenciesView(Adw.Bin): - __gtype_name__ = "DetailsDependencies" +@Gtk.Template(resource_path="/com/usebottles/bottles/details-dependencies-view.ui") +class DetailsDependenciesView(Adw.Bin): + __gtype_name__ = "DetailsDependenciesView" __registry = [] # region Widgets diff --git a/bottles/frontend/views/meson.build b/bottles/frontend/views/meson.build index 403cddf5d0b..b90899b56d1 100644 --- a/bottles/frontend/views/meson.build +++ b/bottles/frontend/views/meson.build @@ -13,7 +13,7 @@ bottles_sources = [ 'bottle_details_page.py', 'bottle_installers.py', - 'bottle_dependencies.py', + 'details_dependencies_view.py', 'details_preferences_page.py', 'details_versioning_page.py', 'details_task_manager_view.py' diff --git a/po/POTFILES b/po/POTFILES index cbb83d78be1..2a6bcfe89c8 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -9,7 +9,7 @@ bottles/frontend/ui/about.blp bottles/frontend/ui/component-entry-row.blp bottles/frontend/ui/dependency-entry-row.blp bottles/frontend/ui/bottle-details-page.blp -bottles/frontend/ui/details-dependencies.blp +bottles/frontend/ui/details-dependencies-view.blp bottles/frontend/ui/details-installers.blp bottles/frontend/ui/details-preferences-page.blp bottles/frontend/ui/details-task-manager-view.blp From e4d8c02762e926e20c7a58f6ce28bf4fa95387d1 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Sun, 12 Jan 2025 15:17:47 -0500 Subject: [PATCH 019/146] details-installers-view: Rename files and class name --- bottles/frontend/ui/bottles.gresource.xml | 2 +- ...ails-installers.blp => details-installers-view.blp} | 2 +- bottles/frontend/ui/meson.build | 2 +- bottles/frontend/views/bottle_details_view.py | 4 ++-- ...bottle_installers.py => details_installers_view.py} | 10 +++++----- bottles/frontend/views/meson.build | 2 +- po/POTFILES | 2 +- 7 files changed, 12 insertions(+), 12 deletions(-) rename bottles/frontend/ui/{details-installers.blp => details-installers-view.blp} (97%) rename bottles/frontend/views/{bottle_installers.py => details_installers_view.py} (96%) diff --git a/bottles/frontend/ui/bottles.gresource.xml b/bottles/frontend/ui/bottles.gresource.xml index d7bdfcfebd0..bd84ecf954f 100644 --- a/bottles/frontend/ui/bottles.gresource.xml +++ b/bottles/frontend/ui/bottles.gresource.xml @@ -26,7 +26,7 @@ bottle-details-view.ui bottle-details-page.ui details-dependencies-view.ui - details-installers.ui + details-installers-view.ui details-preferences-page.ui details-versioning-page.ui details-task-manager-view.ui diff --git a/bottles/frontend/ui/details-installers.blp b/bottles/frontend/ui/details-installers-view.blp similarity index 97% rename from bottles/frontend/ui/details-installers.blp rename to bottles/frontend/ui/details-installers-view.blp index 26de77fd262..c4dec9dcb5b 100644 --- a/bottles/frontend/ui/details-installers.blp +++ b/bottles/frontend/ui/details-installers-view.blp @@ -1,7 +1,7 @@ using Gtk 4.0; using Adw 1; -template $DetailsInstallers: Adw.Bin { +template $DetailsInstallersView: Adw.Bin { Box { orientation: vertical; diff --git a/bottles/frontend/ui/meson.build b/bottles/frontend/ui/meson.build index ea27c696210..3f65f39a595 100644 --- a/bottles/frontend/ui/meson.build +++ b/bottles/frontend/ui/meson.build @@ -7,7 +7,7 @@ blueprints = custom_target('blueprints', 'dependency-entry-row.blp', 'bottle-details-page.blp', 'details-dependencies-view.blp', - 'details-installers.blp', + 'details-installers-view.blp', 'details-task-manager-view.blp', 'details-versioning-page.blp', 'bottle-details-view.blp', diff --git a/bottles/frontend/views/bottle_details_view.py b/bottles/frontend/views/bottle_details_view.py index f55fa51378b..92285f2e80f 100644 --- a/bottles/frontend/views/bottle_details_view.py +++ b/bottles/frontend/views/bottle_details_view.py @@ -27,7 +27,7 @@ from bottles.backend.utils.threading import RunAsync from bottles.frontend.utils.gtk import GtkUtils from bottles.frontend.views.bottle_details_page import BottleDetailsPage -from bottles.frontend.views.bottle_installers import InstallersView +from bottles.frontend.views.details_installers_view import DetailsInstallersView from bottles.frontend.views.details_dependencies_view import DetailsDependenciesView from bottles.frontend.views.details_preferences_page import DetailsPreferencesPage from bottles.frontend.views.details_versioning_page import DetailsVersioningPage @@ -76,7 +76,7 @@ def __init__(self, window, config: Optional[BottleConfig] = None, **kwargs): self.queue = QueueManager(add_fn=self.lock_back, end_fn=self.unlock_back) self.view_bottle = BottleDetailsPage(self, config) - self.view_installers = InstallersView(self, config) + self.view_installers = DetailsInstallersView(self, config) self.view_dependencies = DetailsDependenciesView(self, config) self.view_preferences = DetailsPreferencesPage(self, config) self.view_versioning = DetailsVersioningPage(self, config) diff --git a/bottles/frontend/views/bottle_installers.py b/bottles/frontend/views/details_installers_view.py similarity index 96% rename from bottles/frontend/views/bottle_installers.py rename to bottles/frontend/views/details_installers_view.py index 8d83ca00ab3..16513653cf1 100644 --- a/bottles/frontend/views/bottle_installers.py +++ b/bottles/frontend/views/details_installers_view.py @@ -1,6 +1,6 @@ -# bottle_installers.py +# details_installers_view.py # -# Copyright 2022 brombinmirko +# Copyright 2025 The Bottle Contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -26,9 +26,9 @@ from bottles.frontend.widgets.installer import InstallerEntry -@Gtk.Template(resource_path="/com/usebottles/bottles/details-installers.ui") -class InstallersView(Adw.Bin): - __gtype_name__ = "DetailsInstallers" +@Gtk.Template(resource_path="/com/usebottles/bottles/details-installers-view.ui") +class DetailsInstallersView(Adw.Bin): + __gtype_name__ = "DetailsInstallersView" __registry = [] # region Widgets diff --git a/bottles/frontend/views/meson.build b/bottles/frontend/views/meson.build index b90899b56d1..a2dbe3e8e8c 100644 --- a/bottles/frontend/views/meson.build +++ b/bottles/frontend/views/meson.build @@ -12,7 +12,7 @@ bottles_sources = [ 'loading.py', 'bottle_details_page.py', - 'bottle_installers.py', + 'details_installers_view.py', 'details_dependencies_view.py', 'details_preferences_page.py', 'details_versioning_page.py', diff --git a/po/POTFILES b/po/POTFILES index 2a6bcfe89c8..d421d34fa3e 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -10,7 +10,7 @@ bottles/frontend/ui/component-entry-row.blp bottles/frontend/ui/dependency-entry-row.blp bottles/frontend/ui/bottle-details-page.blp bottles/frontend/ui/details-dependencies-view.blp -bottles/frontend/ui/details-installers.blp +bottles/frontend/ui/details-installers-view.blp bottles/frontend/ui/details-preferences-page.blp bottles/frontend/ui/details-task-manager-view.blp bottles/frontend/ui/details-versioning-page.blp From a5fcad379c377bcddb71704054777b5e5d71b824 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Sun, 12 Jan 2025 15:22:04 -0500 Subject: [PATCH 020/146] dependencies-check-dialog: Rename files --- bottles/frontend/ui/bottles.gresource.xml | 2 +- ...{dialog-deps-check.blp => dependencies-check-dialog.blp} | 0 bottles/frontend/ui/meson.build | 2 +- .../windows/{depscheck.py => dependencies_check_dialog.py} | 6 +++--- bottles/frontend/windows/meson.build | 2 +- bottles/frontend/windows/window.py | 2 +- po/POTFILES | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) rename bottles/frontend/ui/{dialog-deps-check.blp => dependencies-check-dialog.blp} (100%) rename bottles/frontend/windows/{depscheck.py => dependencies_check_dialog.py} (87%) diff --git a/bottles/frontend/ui/bottles.gresource.xml b/bottles/frontend/ui/bottles.gresource.xml index bd84ecf954f..09987112f4a 100644 --- a/bottles/frontend/ui/bottles.gresource.xml +++ b/bottles/frontend/ui/bottles.gresource.xml @@ -50,7 +50,7 @@ dialog-installer.ui bottle-picker-dialog.ui dialog-proton-alert.ui - dialog-deps-check.ui + dependencies-check-dialog.ui dialog-exclusion-patterns.ui dialog-upgrade-versioning.ui dialog-vmtouch.ui diff --git a/bottles/frontend/ui/dialog-deps-check.blp b/bottles/frontend/ui/dependencies-check-dialog.blp similarity index 100% rename from bottles/frontend/ui/dialog-deps-check.blp rename to bottles/frontend/ui/dependencies-check-dialog.blp diff --git a/bottles/frontend/ui/meson.build b/bottles/frontend/ui/meson.build index 3f65f39a595..e6bd8e141ff 100644 --- a/bottles/frontend/ui/meson.build +++ b/bottles/frontend/ui/meson.build @@ -13,7 +13,7 @@ blueprints = custom_target('blueprints', 'bottle-details-view.blp', 'bottle-picker-dialog.blp', 'crash-report-dialog.blp', - 'dialog-deps-check.blp', + 'dependencies-check-dialog.blp', 'dialog-dll-overrides.blp', 'dialog-drives.blp', 'dialog-duplicate.blp', diff --git a/bottles/frontend/windows/depscheck.py b/bottles/frontend/windows/dependencies_check_dialog.py similarity index 87% rename from bottles/frontend/windows/depscheck.py rename to bottles/frontend/windows/dependencies_check_dialog.py index 9e4b7186bc3..e8653b93020 100644 --- a/bottles/frontend/windows/depscheck.py +++ b/bottles/frontend/windows/dependencies_check_dialog.py @@ -1,6 +1,6 @@ -# depscheck.py +# dependencies_check_dialog.py # -# Copyright 2022 brombinmirko +# Copyright 2025 The Bottles Contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -18,7 +18,7 @@ from gi.repository import Gtk, Adw -@Gtk.Template(resource_path="/com/usebottles/bottles/dialog-deps-check.ui") +@Gtk.Template(resource_path="/com/usebottles/bottles/dependencies-check-dialog.ui") class DependenciesCheckDialog(Adw.Window): __gtype_name__ = "DependenciesCheckDialog" diff --git a/bottles/frontend/windows/meson.build b/bottles/frontend/windows/meson.build index 34635aeb3bf..9e35bcac3d5 100644 --- a/bottles/frontend/windows/meson.build +++ b/bottles/frontend/windows/meson.build @@ -23,7 +23,7 @@ bottles_sources = [ 'protonalert.py', 'sandbox.py', 'installer.py', - 'depscheck.py', + 'dependencies_check_dialog.py', 'exclusionpatterns.py', 'upgradeversioning.py', 'vmtouch.py', diff --git a/bottles/frontend/windows/window.py b/bottles/frontend/windows/window.py index aa43bb0733a..8465f868507 100644 --- a/bottles/frontend/windows/window.py +++ b/bottles/frontend/windows/window.py @@ -44,7 +44,7 @@ from bottles.frontend.views.new_bottle_dialog import NewBottleDialog from bottles.frontend.views.preferences import PreferencesWindow from bottles.frontend.windows.crash_report_dialog import CrashReportDialog -from bottles.frontend.windows.depscheck import DependenciesCheckDialog +from bottles.frontend.windows.dependencies_check_dialog import DependenciesCheckDialog from bottles.frontend.windows.onboard import OnboardDialog logging = Logger() diff --git a/po/POTFILES b/po/POTFILES index d421d34fa3e..dd975e241e5 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -17,7 +17,7 @@ bottles/frontend/ui/details-versioning-page.blp bottles/frontend/ui/bottle-details-view.blp bottles/frontend/ui/bottle-picker-dialog.blp bottles/frontend/ui/crash-report-dialog.blp -bottles/frontend/ui/dialog-deps-check.blp +bottles/frontend/ui/dependencies-check-dialog.blp bottles/frontend/ui/dialog-dll-overrides.blp bottles/frontend/ui/dialog-drives.blp bottles/frontend/ui/dialog-duplicate.blp From 6cda10f76e2ca3bb0e76fb359c4aa3337c637d3c Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Sun, 12 Jan 2025 15:25:33 -0500 Subject: [PATCH 021/146] display-dialog: Rename files --- bottles/frontend/ui/bottles.gresource.xml | 2 +- .../frontend/ui/{dialog-display.blp => display-dialog.blp} | 0 bottles/frontend/ui/meson.build | 2 +- bottles/frontend/views/details_preferences_page.py | 2 +- bottles/frontend/windows/{display.py => display_dialog.py} | 6 +++--- bottles/frontend/windows/meson.build | 2 +- po/POTFILES | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) rename bottles/frontend/ui/{dialog-display.blp => display-dialog.blp} (100%) rename bottles/frontend/windows/{display.py => display_dialog.py} (98%) diff --git a/bottles/frontend/ui/bottles.gresource.xml b/bottles/frontend/ui/bottles.gresource.xml index 09987112f4a..60090cacba9 100644 --- a/bottles/frontend/ui/bottles.gresource.xml +++ b/bottles/frontend/ui/bottles.gresource.xml @@ -43,7 +43,7 @@ dialog-vkbasalt.ui dialog-fsr.ui dialog-mangohud.ui - dialog-display.ui + display-dialog.ui dialog-drives.ui dialog-journal.ui dialog-sandbox.ui diff --git a/bottles/frontend/ui/dialog-display.blp b/bottles/frontend/ui/display-dialog.blp similarity index 100% rename from bottles/frontend/ui/dialog-display.blp rename to bottles/frontend/ui/display-dialog.blp diff --git a/bottles/frontend/ui/meson.build b/bottles/frontend/ui/meson.build index e6bd8e141ff..c840ddb9bf5 100644 --- a/bottles/frontend/ui/meson.build +++ b/bottles/frontend/ui/meson.build @@ -28,7 +28,7 @@ blueprints = custom_target('blueprints', 'dialog-sandbox.blp', 'dialog-upgrade-versioning.blp', 'dialog-vkbasalt.blp', - 'dialog-display.blp', + 'display-dialog.blp', 'dialog-vmtouch.blp', 'dialog-fsr.blp', 'dialog-mangohud.blp', diff --git a/bottles/frontend/views/details_preferences_page.py b/bottles/frontend/views/details_preferences_page.py index 77a65cc4395..8a40b71635b 100644 --- a/bottles/frontend/views/details_preferences_page.py +++ b/bottles/frontend/views/details_preferences_page.py @@ -43,7 +43,7 @@ from bottles.backend.utils.threading import RunAsync from bottles.backend.wine.regkeys import RegKeys from bottles.frontend.utils.gtk import GtkUtils -from bottles.frontend.windows.display import DisplayDialog +from bottles.frontend.windows.display_dialog import DisplayDialog from bottles.frontend.windows.dlloverrides import DLLOverridesDialog from bottles.frontend.windows.drives import DrivesDialog from bottles.frontend.windows.envvars import EnvironmentVariablesDialog diff --git a/bottles/frontend/windows/display.py b/bottles/frontend/windows/display_dialog.py similarity index 98% rename from bottles/frontend/windows/display.py rename to bottles/frontend/windows/display_dialog.py index 2948d913b14..0d6ce738062 100644 --- a/bottles/frontend/windows/display.py +++ b/bottles/frontend/windows/display_dialog.py @@ -1,6 +1,6 @@ -# display.py +# display_dialog.py # -# Copyright 2022 Bottles Developers +# Copyright 2025 The Bottles Contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -30,7 +30,7 @@ renderers = ["gl", "gdi", "vulkan"] -@Gtk.Template(resource_path="/com/usebottles/bottles/dialog-display.ui") +@Gtk.Template(resource_path="/com/usebottles/bottles/display-dialog.ui") class DisplayDialog(Adw.Window): __gtype_name__ = "DisplayDialog" diff --git a/bottles/frontend/windows/meson.build b/bottles/frontend/windows/meson.build index 9e35bcac3d5..5ea4065ae96 100644 --- a/bottles/frontend/windows/meson.build +++ b/bottles/frontend/windows/meson.build @@ -16,7 +16,7 @@ bottles_sources = [ 'vkbasalt.py', 'fsr.py', 'mangohud.py', - 'display.py', + 'display_dialog.py', 'generic_cli.py', 'journal.py', 'bottle_picker_dialog.py', diff --git a/po/POTFILES b/po/POTFILES index dd975e241e5..6dc51b589c0 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -70,7 +70,7 @@ bottles/frontend/widgets/library.py bottles/frontend/widgets/program.py bottles/frontend/widgets/state.py bottles/frontend/windows/crash_report_dialog.py -bottles/frontend/windows/display.py +bottles/frontend/windows/display_dialog.py bottles/frontend/windows/dlloverrides.py bottles/frontend/windows/drives.py bottles/frontend/windows/envvars.py From 8fbea9360bfa10b8f7c0f19d5a7d85b859fa015e Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Sun, 12 Jan 2025 15:27:43 -0500 Subject: [PATCH 022/146] dll-overrides-dialog: Rename files --- bottles/frontend/ui/bottles.gresource.xml | 2 +- .../{dialog-dll-overrides.blp => dll-overrides-dialog.blp} | 0 bottles/frontend/ui/meson.build | 2 +- bottles/frontend/views/details_preferences_page.py | 2 +- .../windows/{dlloverrides.py => dll_overrides_dialog.py} | 6 +++--- bottles/frontend/windows/meson.build | 2 +- po/POTFILES | 4 ++-- 7 files changed, 9 insertions(+), 9 deletions(-) rename bottles/frontend/ui/{dialog-dll-overrides.blp => dll-overrides-dialog.blp} (100%) rename bottles/frontend/windows/{dlloverrides.py => dll_overrides_dialog.py} (97%) diff --git a/bottles/frontend/ui/bottles.gresource.xml b/bottles/frontend/ui/bottles.gresource.xml index 60090cacba9..1d9840ceb07 100644 --- a/bottles/frontend/ui/bottles.gresource.xml +++ b/bottles/frontend/ui/bottles.gresource.xml @@ -34,7 +34,7 @@ importer.ui library.ui dialog-launch-options.ui - dialog-dll-overrides.ui + dll-overrides-dialog.ui dialog-env-vars.ui crash-report-dialog.ui dialog-duplicate.ui diff --git a/bottles/frontend/ui/dialog-dll-overrides.blp b/bottles/frontend/ui/dll-overrides-dialog.blp similarity index 100% rename from bottles/frontend/ui/dialog-dll-overrides.blp rename to bottles/frontend/ui/dll-overrides-dialog.blp diff --git a/bottles/frontend/ui/meson.build b/bottles/frontend/ui/meson.build index c840ddb9bf5..f91c1869ac1 100644 --- a/bottles/frontend/ui/meson.build +++ b/bottles/frontend/ui/meson.build @@ -14,7 +14,7 @@ blueprints = custom_target('blueprints', 'bottle-picker-dialog.blp', 'crash-report-dialog.blp', 'dependencies-check-dialog.blp', - 'dialog-dll-overrides.blp', + 'dll-overrides-dialog.blp', 'dialog-drives.blp', 'dialog-duplicate.blp', 'dialog-env-vars.blp', diff --git a/bottles/frontend/views/details_preferences_page.py b/bottles/frontend/views/details_preferences_page.py index 8a40b71635b..70f162a34d8 100644 --- a/bottles/frontend/views/details_preferences_page.py +++ b/bottles/frontend/views/details_preferences_page.py @@ -44,7 +44,7 @@ from bottles.backend.wine.regkeys import RegKeys from bottles.frontend.utils.gtk import GtkUtils from bottles.frontend.windows.display_dialog import DisplayDialog -from bottles.frontend.windows.dlloverrides import DLLOverridesDialog +from bottles.frontend.windows.dll_overrides_dialog import DLLOverridesDialog from bottles.frontend.windows.drives import DrivesDialog from bottles.frontend.windows.envvars import EnvironmentVariablesDialog from bottles.frontend.windows.exclusionpatterns import ExclusionPatternsDialog diff --git a/bottles/frontend/windows/dlloverrides.py b/bottles/frontend/windows/dll_overrides_dialog.py similarity index 97% rename from bottles/frontend/windows/dlloverrides.py rename to bottles/frontend/windows/dll_overrides_dialog.py index 5cf47082e71..0229554a14c 100644 --- a/bottles/frontend/windows/dlloverrides.py +++ b/bottles/frontend/windows/dll_overrides_dialog.py @@ -1,6 +1,6 @@ -# dlloverrides.py +# dll_overrides_dialog.py # -# Copyright 2022 brombinmirko +# Copyright 2025 The Bottles Contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -81,7 +81,7 @@ def __remove_override(self, *_args): self.get_parent().remove(self) -@Gtk.Template(resource_path="/com/usebottles/bottles/dialog-dll-overrides.ui") +@Gtk.Template(resource_path="/com/usebottles/bottles/dll-overrides-dialog.ui") class DLLOverridesDialog(Adw.PreferencesWindow): __gtype_name__ = "DLLOverridesDialog" diff --git a/bottles/frontend/windows/meson.build b/bottles/frontend/windows/meson.build index 5ea4065ae96..8dda72df180 100644 --- a/bottles/frontend/windows/meson.build +++ b/bottles/frontend/windows/meson.build @@ -4,7 +4,7 @@ dialogsdir = join_paths(pkgdatadir, 'bottles/frontend/windows') bottles_sources = [ '__init__.py', 'crash_report_dialog.py', - 'dlloverrides.py', + 'dll_overrides_dialog.py', 'duplicate.py', 'envvars.py', 'generic.py', diff --git a/po/POTFILES b/po/POTFILES index 6dc51b589c0..ae51813dde2 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -18,7 +18,7 @@ bottles/frontend/ui/bottle-details-view.blp bottles/frontend/ui/bottle-picker-dialog.blp bottles/frontend/ui/crash-report-dialog.blp bottles/frontend/ui/dependencies-check-dialog.blp -bottles/frontend/ui/dialog-dll-overrides.blp +bottles/frontend/ui/dll-overrides-dialog.blp bottles/frontend/ui/dialog-drives.blp bottles/frontend/ui/dialog-duplicate.blp bottles/frontend/ui/dialog-env-vars.blp @@ -71,7 +71,7 @@ bottles/frontend/widgets/program.py bottles/frontend/widgets/state.py bottles/frontend/windows/crash_report_dialog.py bottles/frontend/windows/display_dialog.py -bottles/frontend/windows/dlloverrides.py +bottles/frontend/windows/dll_overrides_dialog.py bottles/frontend/windows/drives.py bottles/frontend/windows/envvars.py bottles/frontend/windows/exclusionpatterns.py From 8e17eec08d047e7b9146b868ddabbb345b452b46 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Sun, 12 Jan 2025 15:30:21 -0500 Subject: [PATCH 023/146] drives-dialog: Rename files --- bottles/frontend/ui/bottles.gresource.xml | 2 +- .../frontend/ui/{dialog-drives.blp => drives-dialog.blp} | 0 bottles/frontend/ui/meson.build | 2 +- bottles/frontend/views/details_preferences_page.py | 1 + bottles/frontend/windows/{drives.py => drives_dialog.py} | 6 +++--- bottles/frontend/windows/meson.build | 2 +- po/POTFILES | 4 ++-- 7 files changed, 9 insertions(+), 8 deletions(-) rename bottles/frontend/ui/{dialog-drives.blp => drives-dialog.blp} (100%) rename bottles/frontend/windows/{drives.py => drives_dialog.py} (97%) diff --git a/bottles/frontend/ui/bottles.gresource.xml b/bottles/frontend/ui/bottles.gresource.xml index 1d9840ceb07..b4c538c356d 100644 --- a/bottles/frontend/ui/bottles.gresource.xml +++ b/bottles/frontend/ui/bottles.gresource.xml @@ -44,7 +44,7 @@ dialog-fsr.ui dialog-mangohud.ui display-dialog.ui - dialog-drives.ui + drives-dialog.ui dialog-journal.ui dialog-sandbox.ui dialog-installer.ui diff --git a/bottles/frontend/ui/dialog-drives.blp b/bottles/frontend/ui/drives-dialog.blp similarity index 100% rename from bottles/frontend/ui/dialog-drives.blp rename to bottles/frontend/ui/drives-dialog.blp diff --git a/bottles/frontend/ui/meson.build b/bottles/frontend/ui/meson.build index f91c1869ac1..f3c58268ca8 100644 --- a/bottles/frontend/ui/meson.build +++ b/bottles/frontend/ui/meson.build @@ -15,7 +15,7 @@ blueprints = custom_target('blueprints', 'crash-report-dialog.blp', 'dependencies-check-dialog.blp', 'dll-overrides-dialog.blp', - 'dialog-drives.blp', + 'drives-dialog.blp', 'dialog-duplicate.blp', 'dialog-env-vars.blp', 'dialog-exclusion-patterns.blp', diff --git a/bottles/frontend/views/details_preferences_page.py b/bottles/frontend/views/details_preferences_page.py index 70f162a34d8..3673afb64f9 100644 --- a/bottles/frontend/views/details_preferences_page.py +++ b/bottles/frontend/views/details_preferences_page.py @@ -45,6 +45,7 @@ from bottles.frontend.utils.gtk import GtkUtils from bottles.frontend.windows.display_dialog import DisplayDialog from bottles.frontend.windows.dll_overrides_dialog import DLLOverridesDialog +from bottles.frontend.windows.drives_dialog import DrivesDialog from bottles.frontend.windows.drives import DrivesDialog from bottles.frontend.windows.envvars import EnvironmentVariablesDialog from bottles.frontend.windows.exclusionpatterns import ExclusionPatternsDialog diff --git a/bottles/frontend/windows/drives.py b/bottles/frontend/windows/drives_dialog.py similarity index 97% rename from bottles/frontend/windows/drives.py rename to bottles/frontend/windows/drives_dialog.py index 1cbc9295028..c2752caa028 100644 --- a/bottles/frontend/windows/drives.py +++ b/bottles/frontend/windows/drives_dialog.py @@ -1,6 +1,6 @@ -# drive.py +# drives_dialog.py # -# Copyright 2022 brombinmirko +# Copyright 2025 The Bottle Contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -84,7 +84,7 @@ def __remove(self, *_args): self.parent.add_combo_letter(self.drive[0]) -@Gtk.Template(resource_path="/com/usebottles/bottles/dialog-drives.ui") +@Gtk.Template(resource_path="/com/usebottles/bottles/drives-dialog.ui") class DrivesDialog(Adw.Window): __gtype_name__ = "DrivesDialog" __alphabet = string.ascii_uppercase diff --git a/bottles/frontend/windows/meson.build b/bottles/frontend/windows/meson.build index 8dda72df180..b7c52c9438b 100644 --- a/bottles/frontend/windows/meson.build +++ b/bottles/frontend/windows/meson.build @@ -11,7 +11,7 @@ bottles_sources = [ 'launchoptions.py', 'onboard.py', 'rename.py', - 'drives.py', + 'drives_dialog.py', 'gamescope.py', 'vkbasalt.py', 'fsr.py', diff --git a/po/POTFILES b/po/POTFILES index ae51813dde2..d7e40ac9054 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -19,7 +19,7 @@ bottles/frontend/ui/bottle-picker-dialog.blp bottles/frontend/ui/crash-report-dialog.blp bottles/frontend/ui/dependencies-check-dialog.blp bottles/frontend/ui/dll-overrides-dialog.blp -bottles/frontend/ui/dialog-drives.blp +bottles/frontend/ui/drives-dialog.blp bottles/frontend/ui/dialog-duplicate.blp bottles/frontend/ui/dialog-env-vars.blp bottles/frontend/ui/dialog-exclusion-patterns.blp @@ -72,7 +72,7 @@ bottles/frontend/widgets/state.py bottles/frontend/windows/crash_report_dialog.py bottles/frontend/windows/display_dialog.py bottles/frontend/windows/dll_overrides_dialog.py -bottles/frontend/windows/drives.py +bottles/frontend/windows/drives_dialog.py bottles/frontend/windows/envvars.py bottles/frontend/windows/exclusionpatterns.py bottles/frontend/windows/generic.py From 4f46b2cb661e11a2c629ef74204c32d325e8b6f3 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Sun, 12 Jan 2025 15:32:49 -0500 Subject: [PATCH 024/146] duplicate-dialog: Rename files --- bottles/frontend/ui/bottles.gresource.xml | 2 +- .../ui/{dialog-duplicate.blp => duplicate-dialog.blp} | 0 bottles/frontend/ui/meson.build | 2 +- bottles/frontend/views/bottle_details_page.py | 2 +- .../frontend/windows/{duplicate.py => duplicate_dialog.py} | 6 +++--- bottles/frontend/windows/meson.build | 2 +- po/POTFILES | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) rename bottles/frontend/ui/{dialog-duplicate.blp => duplicate-dialog.blp} (100%) rename bottles/frontend/windows/{duplicate.py => duplicate_dialog.py} (95%) diff --git a/bottles/frontend/ui/bottles.gresource.xml b/bottles/frontend/ui/bottles.gresource.xml index b4c538c356d..6bf024cc9a2 100644 --- a/bottles/frontend/ui/bottles.gresource.xml +++ b/bottles/frontend/ui/bottles.gresource.xml @@ -37,7 +37,7 @@ dll-overrides-dialog.ui dialog-env-vars.ui crash-report-dialog.ui - dialog-duplicate.ui + duplicate-dialog.ui dialog-rename.ui dialog-gamescope.ui dialog-vkbasalt.ui diff --git a/bottles/frontend/ui/dialog-duplicate.blp b/bottles/frontend/ui/duplicate-dialog.blp similarity index 100% rename from bottles/frontend/ui/dialog-duplicate.blp rename to bottles/frontend/ui/duplicate-dialog.blp diff --git a/bottles/frontend/ui/meson.build b/bottles/frontend/ui/meson.build index f3c58268ca8..85494d09780 100644 --- a/bottles/frontend/ui/meson.build +++ b/bottles/frontend/ui/meson.build @@ -16,7 +16,7 @@ blueprints = custom_target('blueprints', 'dependencies-check-dialog.blp', 'dll-overrides-dialog.blp', 'drives-dialog.blp', - 'dialog-duplicate.blp', + 'duplicate-dialog.blp', 'dialog-env-vars.blp', 'dialog-exclusion-patterns.blp', 'dialog-gamescope.blp', diff --git a/bottles/frontend/views/bottle_details_page.py b/bottles/frontend/views/bottle_details_page.py index 57cd03a383b..62f237fc4bf 100644 --- a/bottles/frontend/views/bottle_details_page.py +++ b/bottles/frontend/views/bottle_details_page.py @@ -42,7 +42,7 @@ from bottles.frontend.utils.filters import add_executable_filters, add_all_filters from bottles.frontend.utils.gtk import GtkUtils from bottles.frontend.widgets.program import ProgramEntry -from bottles.frontend.windows.duplicate import DuplicateDialog +from bottles.frontend.windows.duplicate_dialog import DuplicateDialog from bottles.frontend.windows.upgradeversioning import UpgradeVersioningDialog diff --git a/bottles/frontend/windows/duplicate.py b/bottles/frontend/windows/duplicate_dialog.py similarity index 95% rename from bottles/frontend/windows/duplicate.py rename to bottles/frontend/windows/duplicate_dialog.py index 9f69e9cd55e..31c70539bbe 100644 --- a/bottles/frontend/windows/duplicate.py +++ b/bottles/frontend/windows/duplicate_dialog.py @@ -1,6 +1,6 @@ -# duplicate.py +# duplicate_dialog.py # -# Copyright 2022 brombinmirko +# Copyright 2025 The Bottles Contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -24,7 +24,7 @@ from bottles.frontend.utils.gtk import GtkUtils -@Gtk.Template(resource_path="/com/usebottles/bottles/dialog-duplicate.ui") +@Gtk.Template(resource_path="/com/usebottles/bottles/duplicate-dialog.ui") class DuplicateDialog(Adw.Window): __gtype_name__ = "DuplicateDialog" diff --git a/bottles/frontend/windows/meson.build b/bottles/frontend/windows/meson.build index b7c52c9438b..a345f08a9c6 100644 --- a/bottles/frontend/windows/meson.build +++ b/bottles/frontend/windows/meson.build @@ -5,7 +5,7 @@ bottles_sources = [ '__init__.py', 'crash_report_dialog.py', 'dll_overrides_dialog.py', - 'duplicate.py', + 'duplicate_dialog.py', 'envvars.py', 'generic.py', 'launchoptions.py', diff --git a/po/POTFILES b/po/POTFILES index d7e40ac9054..8e166e945c0 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -20,7 +20,7 @@ bottles/frontend/ui/crash-report-dialog.blp bottles/frontend/ui/dependencies-check-dialog.blp bottles/frontend/ui/dll-overrides-dialog.blp bottles/frontend/ui/drives-dialog.blp -bottles/frontend/ui/dialog-duplicate.blp +bottles/frontend/ui/duplicate-dialog.blp bottles/frontend/ui/dialog-env-vars.blp bottles/frontend/ui/dialog-exclusion-patterns.blp bottles/frontend/ui/dialog-gamescope.blp From a762b6822e3ea92f19d79b6b16780f3e68e5acac Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Sun, 12 Jan 2025 18:27:40 -0500 Subject: [PATCH 025/146] exclusion-patterns-dialog: Rename files --- bottles/frontend/ui/bottles.gresource.xml | 2 +- ...exclusion-patterns.blp => exclusion-patterns-dialog.blp} | 0 bottles/frontend/ui/meson.build | 2 +- bottles/frontend/views/details_preferences_page.py | 3 +-- .../{exclusionpatterns.py => exclusion_patterns_dialog.py} | 6 +++--- bottles/frontend/windows/meson.build | 2 +- po/POTFILES | 4 ++-- 7 files changed, 9 insertions(+), 10 deletions(-) rename bottles/frontend/ui/{dialog-exclusion-patterns.blp => exclusion-patterns-dialog.blp} (100%) rename bottles/frontend/windows/{exclusionpatterns.py => exclusion_patterns_dialog.py} (95%) diff --git a/bottles/frontend/ui/bottles.gresource.xml b/bottles/frontend/ui/bottles.gresource.xml index 6bf024cc9a2..12148b88e54 100644 --- a/bottles/frontend/ui/bottles.gresource.xml +++ b/bottles/frontend/ui/bottles.gresource.xml @@ -51,7 +51,7 @@ bottle-picker-dialog.ui dialog-proton-alert.ui dependencies-check-dialog.ui - dialog-exclusion-patterns.ui + exclusion-patterns-dialog.ui dialog-upgrade-versioning.ui dialog-vmtouch.ui onboard.ui diff --git a/bottles/frontend/ui/dialog-exclusion-patterns.blp b/bottles/frontend/ui/exclusion-patterns-dialog.blp similarity index 100% rename from bottles/frontend/ui/dialog-exclusion-patterns.blp rename to bottles/frontend/ui/exclusion-patterns-dialog.blp diff --git a/bottles/frontend/ui/meson.build b/bottles/frontend/ui/meson.build index 85494d09780..13a78edc6cb 100644 --- a/bottles/frontend/ui/meson.build +++ b/bottles/frontend/ui/meson.build @@ -18,7 +18,7 @@ blueprints = custom_target('blueprints', 'drives-dialog.blp', 'duplicate-dialog.blp', 'dialog-env-vars.blp', - 'dialog-exclusion-patterns.blp', + 'exclusion-patterns-dialog.blp', 'dialog-gamescope.blp', 'dialog-installer.blp', 'dialog-journal.blp', diff --git a/bottles/frontend/views/details_preferences_page.py b/bottles/frontend/views/details_preferences_page.py index 3673afb64f9..4d2483eaf72 100644 --- a/bottles/frontend/views/details_preferences_page.py +++ b/bottles/frontend/views/details_preferences_page.py @@ -46,9 +46,8 @@ from bottles.frontend.windows.display_dialog import DisplayDialog from bottles.frontend.windows.dll_overrides_dialog import DLLOverridesDialog from bottles.frontend.windows.drives_dialog import DrivesDialog -from bottles.frontend.windows.drives import DrivesDialog from bottles.frontend.windows.envvars import EnvironmentVariablesDialog -from bottles.frontend.windows.exclusionpatterns import ExclusionPatternsDialog +from bottles.frontend.windows.exclusion_patterns_dialog import ExclusionPatternsDialog from bottles.frontend.windows.fsr import FsrDialog from bottles.frontend.windows.gamescope import GamescopeDialog from bottles.frontend.windows.mangohud import MangoHudDialog diff --git a/bottles/frontend/windows/exclusionpatterns.py b/bottles/frontend/windows/exclusion_patterns_dialog.py similarity index 95% rename from bottles/frontend/windows/exclusionpatterns.py rename to bottles/frontend/windows/exclusion_patterns_dialog.py index 2c7bcdac795..9e57dc8b925 100644 --- a/bottles/frontend/windows/exclusionpatterns.py +++ b/bottles/frontend/windows/exclusion_patterns_dialog.py @@ -1,6 +1,6 @@ -# envvars.py +# exclusion_patterns_dialog.py # -# Copyright 2022 brombinmirko +# Copyright 2025 The Bottles Contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -57,7 +57,7 @@ def __remove(self, *_args): self.parent.group_patterns.remove(self) -@Gtk.Template(resource_path="/com/usebottles/bottles/dialog-exclusion-patterns.ui") +@Gtk.Template(resource_path="/com/usebottles/bottles/exclusion-patterns-dialog.ui") class ExclusionPatternsDialog(Adw.Window): __gtype_name__ = "ExclusionPatternsDialog" diff --git a/bottles/frontend/windows/meson.build b/bottles/frontend/windows/meson.build index a345f08a9c6..0175355e024 100644 --- a/bottles/frontend/windows/meson.build +++ b/bottles/frontend/windows/meson.build @@ -24,7 +24,7 @@ bottles_sources = [ 'sandbox.py', 'installer.py', 'dependencies_check_dialog.py', - 'exclusionpatterns.py', + 'exclusion_patterns_dialog.py', 'upgradeversioning.py', 'vmtouch.py', 'window.py', diff --git a/po/POTFILES b/po/POTFILES index 8e166e945c0..3d48d1a251a 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -22,7 +22,7 @@ bottles/frontend/ui/dll-overrides-dialog.blp bottles/frontend/ui/drives-dialog.blp bottles/frontend/ui/duplicate-dialog.blp bottles/frontend/ui/dialog-env-vars.blp -bottles/frontend/ui/dialog-exclusion-patterns.blp +bottles/frontend/ui/exclusion-patterns-dialog.blp bottles/frontend/ui/dialog-gamescope.blp bottles/frontend/ui/dialog-installer.blp bottles/frontend/ui/dialog-journal.blp @@ -74,7 +74,7 @@ bottles/frontend/windows/display_dialog.py bottles/frontend/windows/dll_overrides_dialog.py bottles/frontend/windows/drives_dialog.py bottles/frontend/windows/envvars.py -bottles/frontend/windows/exclusionpatterns.py +bottles/frontend/windows/exclusion_patterns_dialog.py bottles/frontend/windows/generic.py bottles/frontend/windows/installer.py bottles/frontend/windows/launchoptions.py From b266d17262ecad1742904371cede77526ce2a2be Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Sun, 12 Jan 2025 18:38:20 -0500 Subject: [PATCH 026/146] gamescope-dialog: Rename files --- bottles/frontend/ui/bottles.gresource.xml | 2 +- .../ui/{dialog-gamescope.blp => gamescope-dialog.blp} | 0 bottles/frontend/ui/meson.build | 2 +- bottles/frontend/views/details_preferences_page.py | 2 +- .../frontend/windows/{gamescope.py => gamescope_dialog.py} | 6 +++--- bottles/frontend/windows/meson.build | 2 +- po/POTFILES | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) rename bottles/frontend/ui/{dialog-gamescope.blp => gamescope-dialog.blp} (100%) rename bottles/frontend/windows/{gamescope.py => gamescope_dialog.py} (96%) diff --git a/bottles/frontend/ui/bottles.gresource.xml b/bottles/frontend/ui/bottles.gresource.xml index 12148b88e54..d145daeb6fc 100644 --- a/bottles/frontend/ui/bottles.gresource.xml +++ b/bottles/frontend/ui/bottles.gresource.xml @@ -39,7 +39,7 @@ crash-report-dialog.ui duplicate-dialog.ui dialog-rename.ui - dialog-gamescope.ui + gamescope-dialog.ui dialog-vkbasalt.ui dialog-fsr.ui dialog-mangohud.ui diff --git a/bottles/frontend/ui/dialog-gamescope.blp b/bottles/frontend/ui/gamescope-dialog.blp similarity index 100% rename from bottles/frontend/ui/dialog-gamescope.blp rename to bottles/frontend/ui/gamescope-dialog.blp diff --git a/bottles/frontend/ui/meson.build b/bottles/frontend/ui/meson.build index 13a78edc6cb..c5001895f93 100644 --- a/bottles/frontend/ui/meson.build +++ b/bottles/frontend/ui/meson.build @@ -19,7 +19,7 @@ blueprints = custom_target('blueprints', 'duplicate-dialog.blp', 'dialog-env-vars.blp', 'exclusion-patterns-dialog.blp', - 'dialog-gamescope.blp', + 'gamescope-dialog.blp', 'dialog-installer.blp', 'dialog-journal.blp', 'dialog-launch-options.blp', diff --git a/bottles/frontend/views/details_preferences_page.py b/bottles/frontend/views/details_preferences_page.py index 4d2483eaf72..b53ae0cb3e1 100644 --- a/bottles/frontend/views/details_preferences_page.py +++ b/bottles/frontend/views/details_preferences_page.py @@ -49,7 +49,7 @@ from bottles.frontend.windows.envvars import EnvironmentVariablesDialog from bottles.frontend.windows.exclusion_patterns_dialog import ExclusionPatternsDialog from bottles.frontend.windows.fsr import FsrDialog -from bottles.frontend.windows.gamescope import GamescopeDialog +from bottles.frontend.windows.gamescope_dialog import GamescopeDialog from bottles.frontend.windows.mangohud import MangoHudDialog from bottles.frontend.windows.protonalert import ProtonAlertDialog from bottles.frontend.windows.sandbox import SandboxDialog diff --git a/bottles/frontend/windows/gamescope.py b/bottles/frontend/windows/gamescope_dialog.py similarity index 96% rename from bottles/frontend/windows/gamescope.py rename to bottles/frontend/windows/gamescope_dialog.py index 2e917411c69..f467160dba3 100644 --- a/bottles/frontend/windows/gamescope.py +++ b/bottles/frontend/windows/gamescope_dialog.py @@ -1,6 +1,6 @@ -# gamescope.py +# gamescope_dialog.py # -# Copyright 2022 brombinmirko +# Copyright 2025 The Bottles Contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -18,7 +18,7 @@ from gi.repository import Gtk, GLib, Adw -@Gtk.Template(resource_path="/com/usebottles/bottles/dialog-gamescope.ui") +@Gtk.Template(resource_path="/com/usebottles/bottles/gamescope-dialog.ui") class GamescopeDialog(Adw.Window): __gtype_name__ = "GamescopeDialog" diff --git a/bottles/frontend/windows/meson.build b/bottles/frontend/windows/meson.build index 0175355e024..8bb2c39adbf 100644 --- a/bottles/frontend/windows/meson.build +++ b/bottles/frontend/windows/meson.build @@ -12,7 +12,7 @@ bottles_sources = [ 'onboard.py', 'rename.py', 'drives_dialog.py', - 'gamescope.py', + 'gamescope_dialog.py', 'vkbasalt.py', 'fsr.py', 'mangohud.py', diff --git a/po/POTFILES b/po/POTFILES index 3d48d1a251a..f383954fddd 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -23,7 +23,7 @@ bottles/frontend/ui/drives-dialog.blp bottles/frontend/ui/duplicate-dialog.blp bottles/frontend/ui/dialog-env-vars.blp bottles/frontend/ui/exclusion-patterns-dialog.blp -bottles/frontend/ui/dialog-gamescope.blp +bottles/frontend/ui/gamescope-dialog.blp bottles/frontend/ui/dialog-installer.blp bottles/frontend/ui/dialog-journal.blp bottles/frontend/ui/dialog-launch-options.blp From 508e62601d58eae881ed078a42e8a67dd4e8c426 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Sun, 12 Jan 2025 18:41:53 -0500 Subject: [PATCH 027/146] exclusion-pattern-row: Rename files and class name --- bottles/frontend/ui/bottles.gresource.xml | 2 +- ...ion-pattern-entry.blp => exclusion-pattern-row.blp} | 2 +- bottles/frontend/ui/meson.build | 2 +- bottles/frontend/windows/exclusion_patterns_dialog.py | 10 +++++----- po/POTFILES | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) rename bottles/frontend/ui/{exclusion-pattern-entry.blp => exclusion-pattern-row.blp} (77%) diff --git a/bottles/frontend/ui/bottles.gresource.xml b/bottles/frontend/ui/bottles.gresource.xml index d145daeb6fc..68465d612a0 100644 --- a/bottles/frontend/ui/bottles.gresource.xml +++ b/bottles/frontend/ui/bottles.gresource.xml @@ -22,7 +22,7 @@ drive-entry.ui library-entry.ui local-resource-entry.ui - exclusion-pattern-entry.ui + exclusion-pattern-row.ui bottle-details-view.ui bottle-details-page.ui details-dependencies-view.ui diff --git a/bottles/frontend/ui/exclusion-pattern-entry.blp b/bottles/frontend/ui/exclusion-pattern-row.blp similarity index 77% rename from bottles/frontend/ui/exclusion-pattern-entry.blp rename to bottles/frontend/ui/exclusion-pattern-row.blp index ec6f8c16397..7965fd65882 100644 --- a/bottles/frontend/ui/exclusion-pattern-entry.blp +++ b/bottles/frontend/ui/exclusion-pattern-row.blp @@ -1,7 +1,7 @@ using Gtk 4.0; using Adw 1; -template $ExclusionPatternEntry: Adw.ActionRow { +template $ExclusionPatternRow: Adw.ActionRow { title: _("Value"); Button btn_remove { diff --git a/bottles/frontend/ui/meson.build b/bottles/frontend/ui/meson.build index c5001895f93..e51e49ffbd0 100644 --- a/bottles/frontend/ui/meson.build +++ b/bottles/frontend/ui/meson.build @@ -35,7 +35,7 @@ blueprints = custom_target('blueprints', 'dll-override-entry.blp', 'drive-entry.blp', 'env-var-entry.blp', - 'exclusion-pattern-entry.blp', + 'exclusion-pattern-row.blp', 'importer-entry.blp', 'importer.blp', 'installer-entry.blp', diff --git a/bottles/frontend/windows/exclusion_patterns_dialog.py b/bottles/frontend/windows/exclusion_patterns_dialog.py index 9e57dc8b925..e406a8c954a 100644 --- a/bottles/frontend/windows/exclusion_patterns_dialog.py +++ b/bottles/frontend/windows/exclusion_patterns_dialog.py @@ -20,9 +20,9 @@ from gi.repository import Gtk, GLib, Adw -@Gtk.Template(resource_path="/com/usebottles/bottles/exclusion-pattern-entry.ui") -class ExclusionPatternEntry(Adw.ActionRow): - __gtype_name__ = "ExclusionPatternEntry" +@Gtk.Template(resource_path="/com/usebottles/bottles/exclusion-pattern-row.ui") +class ExclusionPatternRow(Adw.ActionRow): + __gtype_name__ = "ExclusionPatternRow" # region Widgets btn_remove = Gtk.Template.Child() @@ -91,7 +91,7 @@ def __save_var(self, *_args): key="Versioning_Exclusion_Patterns", value=self.config.Versioning_Exclusion_Patterns + [pattern], ) - _entry = ExclusionPatternEntry(self, pattern) + _entry = ExclusionPatternRow(self, pattern) GLib.idle_add(self.group_patterns.add, _entry) self.entry_name.set_text("") @@ -107,5 +107,5 @@ def __populate_patterns_list(self): self.group_patterns.set_description("") for pattern in patterns: - _entry = ExclusionPatternEntry(self, pattern) + _entry = ExclusionPatternRow(self, pattern) GLib.idle_add(self.group_patterns.add, _entry) diff --git a/po/POTFILES b/po/POTFILES index f383954fddd..81519df9c89 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -36,7 +36,7 @@ bottles/frontend/ui/dialog-vkbasalt.blp bottles/frontend/ui/dll-override-entry.blp bottles/frontend/ui/drive-entry.blp bottles/frontend/ui/env-var-entry.blp -bottles/frontend/ui/exclusion-pattern-entry.blp +bottles/frontend/ui/exclusion-pattern-row.blp bottles/frontend/ui/importer-entry.blp bottles/frontend/ui/importer.blp bottles/frontend/ui/installer-entry.blp From 854c31a35ae1dde0caa60ad7eff0ddee2c683b0a Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Sun, 12 Jan 2025 18:45:56 -0500 Subject: [PATCH 028/146] fsr-dialog: Rename files and add to POTFILES --- bottles/frontend/ui/bottles.gresource.xml | 2 +- bottles/frontend/ui/{dialog-fsr.blp => fsr-dialog.blp} | 0 bottles/frontend/ui/meson.build | 2 +- bottles/frontend/views/details_preferences_page.py | 2 +- bottles/frontend/windows/{fsr.py => fsr_dialog.py} | 6 +++--- bottles/frontend/windows/meson.build | 2 +- po/POTFILES | 2 ++ 7 files changed, 9 insertions(+), 7 deletions(-) rename bottles/frontend/ui/{dialog-fsr.blp => fsr-dialog.blp} (100%) rename bottles/frontend/windows/{fsr.py => fsr_dialog.py} (95%) diff --git a/bottles/frontend/ui/bottles.gresource.xml b/bottles/frontend/ui/bottles.gresource.xml index 68465d612a0..6a9cf6863cf 100644 --- a/bottles/frontend/ui/bottles.gresource.xml +++ b/bottles/frontend/ui/bottles.gresource.xml @@ -41,7 +41,7 @@ dialog-rename.ui gamescope-dialog.ui dialog-vkbasalt.ui - dialog-fsr.ui + fsr-dialog.ui dialog-mangohud.ui display-dialog.ui drives-dialog.ui diff --git a/bottles/frontend/ui/dialog-fsr.blp b/bottles/frontend/ui/fsr-dialog.blp similarity index 100% rename from bottles/frontend/ui/dialog-fsr.blp rename to bottles/frontend/ui/fsr-dialog.blp diff --git a/bottles/frontend/ui/meson.build b/bottles/frontend/ui/meson.build index e51e49ffbd0..78288a30ce2 100644 --- a/bottles/frontend/ui/meson.build +++ b/bottles/frontend/ui/meson.build @@ -30,7 +30,7 @@ blueprints = custom_target('blueprints', 'dialog-vkbasalt.blp', 'display-dialog.blp', 'dialog-vmtouch.blp', - 'dialog-fsr.blp', + 'fsr-dialog.blp', 'dialog-mangohud.blp', 'dll-override-entry.blp', 'drive-entry.blp', diff --git a/bottles/frontend/views/details_preferences_page.py b/bottles/frontend/views/details_preferences_page.py index b53ae0cb3e1..09b8cde1389 100644 --- a/bottles/frontend/views/details_preferences_page.py +++ b/bottles/frontend/views/details_preferences_page.py @@ -48,7 +48,7 @@ from bottles.frontend.windows.drives_dialog import DrivesDialog from bottles.frontend.windows.envvars import EnvironmentVariablesDialog from bottles.frontend.windows.exclusion_patterns_dialog import ExclusionPatternsDialog -from bottles.frontend.windows.fsr import FsrDialog +from bottles.frontend.windows.fsr_dialog import FsrDialog from bottles.frontend.windows.gamescope_dialog import GamescopeDialog from bottles.frontend.windows.mangohud import MangoHudDialog from bottles.frontend.windows.protonalert import ProtonAlertDialog diff --git a/bottles/frontend/windows/fsr.py b/bottles/frontend/windows/fsr_dialog.py similarity index 95% rename from bottles/frontend/windows/fsr.py rename to bottles/frontend/windows/fsr_dialog.py index 1c7ce23c43d..e35d83d1bf1 100644 --- a/bottles/frontend/windows/fsr.py +++ b/bottles/frontend/windows/fsr_dialog.py @@ -1,6 +1,6 @@ -# vkbasalt.py +# fsr_dialog.py # -# Copyright 2022 Bottles Contributors +# Copyright 2025 The Bottles Contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -23,7 +23,7 @@ logging = Logger() -@Gtk.Template(resource_path="/com/usebottles/bottles/dialog-fsr.ui") +@Gtk.Template(resource_path="/com/usebottles/bottles/fsr-dialog.ui") class FsrDialog(Adw.Window): __gtype_name__ = "FsrDialog" diff --git a/bottles/frontend/windows/meson.build b/bottles/frontend/windows/meson.build index 8bb2c39adbf..30614edb58c 100644 --- a/bottles/frontend/windows/meson.build +++ b/bottles/frontend/windows/meson.build @@ -14,7 +14,7 @@ bottles_sources = [ 'drives_dialog.py', 'gamescope_dialog.py', 'vkbasalt.py', - 'fsr.py', + 'fsr_dialog.py', 'mangohud.py', 'display_dialog.py', 'generic_cli.py', diff --git a/po/POTFILES b/po/POTFILES index 81519df9c89..f79fb8c92bd 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -53,6 +53,7 @@ bottles/frontend/ui/program-entry.blp bottles/frontend/ui/state-entry.blp bottles/frontend/ui/task-entry.blp bottles/frontend/ui/window.blp +bottles/frontend/ui/fsr-dialog.blp bottles/frontend/views/bottle_details_page.py bottles/frontend/views/details_preferences_page.py bottles/frontend/views/details_versioning_page.py @@ -80,6 +81,7 @@ bottles/frontend/windows/installer.py bottles/frontend/windows/launchoptions.py bottles/frontend/windows/main_window.py bottles/frontend/windows/vkbasalt.py +bottles/frontend/windows/fsr_dialog.py data/com.usebottles.bottles.desktop.in.in data/com.usebottles.bottles.gschema.xml data/com.usebottles.bottles.metainfo.xml.in From 9451be746836b288778f66d6e75a7a5d48bb6ca3 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Sun, 12 Jan 2025 18:56:16 -0500 Subject: [PATCH 029/146] importer-view: Rename files --- bottles/frontend/ui/bottles.gresource.xml | 2 +- bottles/frontend/ui/{importer.blp => importer-view.blp} | 0 bottles/frontend/ui/meson.build | 2 +- bottles/frontend/views/{importer.py => importer_view.py} | 6 +++--- bottles/frontend/views/meson.build | 2 +- bottles/frontend/windows/window.py | 2 +- po/POTFILES | 4 ++-- 7 files changed, 9 insertions(+), 9 deletions(-) rename bottles/frontend/ui/{importer.blp => importer-view.blp} (100%) rename bottles/frontend/views/{importer.py => importer_view.py} (97%) diff --git a/bottles/frontend/ui/bottles.gresource.xml b/bottles/frontend/ui/bottles.gresource.xml index 6a9cf6863cf..523eb1c7642 100644 --- a/bottles/frontend/ui/bottles.gresource.xml +++ b/bottles/frontend/ui/bottles.gresource.xml @@ -31,7 +31,7 @@ details-versioning-page.ui details-task-manager-view.ui preferences.ui - importer.ui + importer-view.ui library.ui dialog-launch-options.ui dll-overrides-dialog.ui diff --git a/bottles/frontend/ui/importer.blp b/bottles/frontend/ui/importer-view.blp similarity index 100% rename from bottles/frontend/ui/importer.blp rename to bottles/frontend/ui/importer-view.blp diff --git a/bottles/frontend/ui/meson.build b/bottles/frontend/ui/meson.build index 78288a30ce2..c563159f36f 100644 --- a/bottles/frontend/ui/meson.build +++ b/bottles/frontend/ui/meson.build @@ -37,7 +37,7 @@ blueprints = custom_target('blueprints', 'env-var-entry.blp', 'exclusion-pattern-row.blp', 'importer-entry.blp', - 'importer.blp', + 'importer-view.blp', 'installer-entry.blp', 'library-entry.blp', 'library.blp', diff --git a/bottles/frontend/views/importer.py b/bottles/frontend/views/importer_view.py similarity index 97% rename from bottles/frontend/views/importer.py rename to bottles/frontend/views/importer_view.py index 4a285736101..552781996c5 100644 --- a/bottles/frontend/views/importer.py +++ b/bottles/frontend/views/importer_view.py @@ -1,6 +1,6 @@ -# importer.py +# importer_view.py # -# Copyright 2022 brombinmirko +# Copyright 2025 The Bottles Contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -26,7 +26,7 @@ from bottles.frontend.widgets.importer import ImporterEntry -@Gtk.Template(resource_path="/com/usebottles/bottles/importer.ui") +@Gtk.Template(resource_path="/com/usebottles/bottles/importer-view.ui") class ImporterView(Adw.Bin): __gtype_name__ = "ImporterView" diff --git a/bottles/frontend/views/meson.build b/bottles/frontend/views/meson.build index a2dbe3e8e8c..38ec9d5fb79 100644 --- a/bottles/frontend/views/meson.build +++ b/bottles/frontend/views/meson.build @@ -8,7 +8,7 @@ bottles_sources = [ 'library.py', 'bottle_details_view.py', 'preferences.py', - 'importer.py', + 'importer_view.py', 'loading.py', 'bottle_details_page.py', diff --git a/bottles/frontend/windows/window.py b/bottles/frontend/windows/window.py index 8465f868507..17338878614 100644 --- a/bottles/frontend/windows/window.py +++ b/bottles/frontend/windows/window.py @@ -37,7 +37,7 @@ from bottles.frontend.params import APP_ID, BASE_ID, PROFILE from bottles.frontend.utils.gtk import GtkUtils from bottles.frontend.views.bottle_details_view import BottleDetailsView -from bottles.frontend.views.importer import ImporterView +from bottles.frontend.views.importer_view import ImporterView from bottles.frontend.views.library import LibraryView from bottles.frontend.views.list import BottleView from bottles.frontend.views.loading import LoadingView diff --git a/po/POTFILES b/po/POTFILES index f79fb8c92bd..7e43e9286ff 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -38,7 +38,7 @@ bottles/frontend/ui/drive-entry.blp bottles/frontend/ui/env-var-entry.blp bottles/frontend/ui/exclusion-pattern-row.blp bottles/frontend/ui/importer-entry.blp -bottles/frontend/ui/importer.blp +bottles/frontend/ui/importer-view.blp bottles/frontend/ui/installer-entry.blp bottles/frontend/ui/library-entry.blp bottles/frontend/ui/library.blp @@ -58,7 +58,7 @@ bottles/frontend/views/bottle_details_page.py bottles/frontend/views/details_preferences_page.py bottles/frontend/views/details_versioning_page.py bottles/frontend/views/bottle_details_view.py -bottles/frontend/views/importer.py +bottles/frontend/views/importer_view.py bottles/frontend/views/list.py bottles/frontend/views/loading.py bottles/frontend/views/new_bottle_dialog.py From 5043948b916e936de634979886f88e43d70ffa1d Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Sun, 12 Jan 2025 18:59:37 -0500 Subject: [PATCH 030/146] importer-row: Rename files and class name --- bottles/frontend/ui/bottles.gresource.xml | 2 +- .../ui/{importer-entry.blp => importer-row.blp} | 2 +- bottles/frontend/ui/meson.build | 2 +- bottles/frontend/views/importer_view.py | 4 ++-- .../frontend/widgets/{importer.py => importer_row.py} | 10 +++++----- bottles/frontend/widgets/meson.build | 2 +- po/POTFILES | 4 ++-- 7 files changed, 13 insertions(+), 13 deletions(-) rename bottles/frontend/ui/{importer-entry.blp => importer-row.blp} (96%) rename bottles/frontend/widgets/{importer.py => importer_row.py} (92%) diff --git a/bottles/frontend/ui/bottles.gresource.xml b/bottles/frontend/ui/bottles.gresource.xml index 523eb1c7642..050a72d85cf 100644 --- a/bottles/frontend/ui/bottles.gresource.xml +++ b/bottles/frontend/ui/bottles.gresource.xml @@ -13,7 +13,7 @@ task-entry.ui dependency-entry-row.ui program-entry.ui - importer-entry.ui + importer-row.ui state-entry.ui installer-entry.ui dll-override-entry.ui diff --git a/bottles/frontend/ui/importer-entry.blp b/bottles/frontend/ui/importer-row.blp similarity index 96% rename from bottles/frontend/ui/importer-entry.blp rename to bottles/frontend/ui/importer-row.blp index 2c42347b6fd..609124e57ae 100644 --- a/bottles/frontend/ui/importer-entry.blp +++ b/bottles/frontend/ui/importer-row.blp @@ -16,7 +16,7 @@ Popover pop_actions { } } -template $ImporterEntry: Adw.ActionRow { +template $ImporterRow: Adw.ActionRow { /* Translators: A Wine prefix is a separate environment (C:\ drive) for the Wine program */ title: _("Wine prefix name"); diff --git a/bottles/frontend/ui/meson.build b/bottles/frontend/ui/meson.build index c563159f36f..55a58636708 100644 --- a/bottles/frontend/ui/meson.build +++ b/bottles/frontend/ui/meson.build @@ -36,7 +36,7 @@ blueprints = custom_target('blueprints', 'drive-entry.blp', 'env-var-entry.blp', 'exclusion-pattern-row.blp', - 'importer-entry.blp', + 'importer-row.blp', 'importer-view.blp', 'installer-entry.blp', 'library-entry.blp', diff --git a/bottles/frontend/views/importer_view.py b/bottles/frontend/views/importer_view.py index 552781996c5..dfc50ecf18d 100644 --- a/bottles/frontend/views/importer_view.py +++ b/bottles/frontend/views/importer_view.py @@ -23,7 +23,7 @@ from bottles.backend.utils.threading import RunAsync from bottles.frontend.utils.filters import add_yaml_filters, add_all_filters from bottles.frontend.utils.gtk import GtkUtils -from bottles.frontend.widgets.importer import ImporterEntry +from bottles.frontend.widgets.importer_row import ImporterRow @Gtk.Template(resource_path="/com/usebottles/bottles/importer-view.ui") @@ -77,7 +77,7 @@ def update(result, error=False): self.list_prefixes.remove(_w) for prefix in result.data.get("wineprefixes"): - self.list_prefixes.append(ImporterEntry(self, prefix)) + self.list_prefixes.append(ImporterRow(self, prefix)) widget.set_sensitive(False) diff --git a/bottles/frontend/widgets/importer.py b/bottles/frontend/widgets/importer_row.py similarity index 92% rename from bottles/frontend/widgets/importer.py rename to bottles/frontend/widgets/importer_row.py index f3e7004a9b3..3fec3da5e46 100644 --- a/bottles/frontend/widgets/importer.py +++ b/bottles/frontend/widgets/importer_row.py @@ -1,6 +1,6 @@ -# importer.py +# importer_row.py # -# Copyright 2022 brombinmirko +# Copyright 2025 The Bottles Contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -24,9 +24,9 @@ from bottles.frontend.utils.gtk import GtkUtils -@Gtk.Template(resource_path="/com/usebottles/bottles/importer-entry.ui") -class ImporterEntry(Adw.ActionRow): - __gtype_name__ = "ImporterEntry" +@Gtk.Template(resource_path="/com/usebottles/bottles/importer-row.ui") +class ImporterRow(Adw.ActionRow): + __gtype_name__ = "ImporterRow" # region Widgets label_manager = Gtk.Template.Child() diff --git a/bottles/frontend/widgets/meson.build b/bottles/frontend/widgets/meson.build index b763a20fe2a..69ce2cd338c 100644 --- a/bottles/frontend/widgets/meson.build +++ b/bottles/frontend/widgets/meson.build @@ -5,7 +5,7 @@ bottles_sources = [ '__init__.py', 'dependency_entry_row.py', 'executable.py', - 'importer.py', + 'importer_row.py', 'installer.py', 'program.py', 'state.py', diff --git a/po/POTFILES b/po/POTFILES index 7e43e9286ff..8ea61011d19 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -37,7 +37,7 @@ bottles/frontend/ui/dll-override-entry.blp bottles/frontend/ui/drive-entry.blp bottles/frontend/ui/env-var-entry.blp bottles/frontend/ui/exclusion-pattern-row.blp -bottles/frontend/ui/importer-entry.blp +bottles/frontend/ui/importer-row.blp bottles/frontend/ui/importer-view.blp bottles/frontend/ui/installer-entry.blp bottles/frontend/ui/library-entry.blp @@ -65,7 +65,7 @@ bottles/frontend/views/new_bottle_dialog.py bottles/frontend/views/preferences.py bottles/frontend/widgets/component.py bottles/frontend/widgets/dependency.py -bottles/frontend/widgets/importer.py +bottles/frontend/widgets/importer_row.py bottles/frontend/widgets/installer.py bottles/frontend/widgets/library.py bottles/frontend/widgets/program.py From 54988cc6a9a8c79aa22b10d19807eafaa5990420 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Sun, 12 Jan 2025 19:02:43 -0500 Subject: [PATCH 031/146] installer-row: Rename files and class name --- bottles/frontend/ui/bottles.gresource.xml | 2 +- .../ui/{installer-entry.blp => installer-row.blp} | 2 +- bottles/frontend/ui/meson.build | 2 +- bottles/frontend/views/details_installers_view.py | 4 ++-- .../widgets/{installer.py => installer_row.py} | 10 +++++----- bottles/frontend/widgets/meson.build | 2 +- po/POTFILES | 4 ++-- 7 files changed, 13 insertions(+), 13 deletions(-) rename bottles/frontend/ui/{installer-entry.blp => installer-row.blp} (96%) rename bottles/frontend/widgets/{installer.py => installer_row.py} (94%) diff --git a/bottles/frontend/ui/bottles.gresource.xml b/bottles/frontend/ui/bottles.gresource.xml index 050a72d85cf..ad2fab6d5fe 100644 --- a/bottles/frontend/ui/bottles.gresource.xml +++ b/bottles/frontend/ui/bottles.gresource.xml @@ -15,7 +15,7 @@ program-entry.ui importer-row.ui state-entry.ui - installer-entry.ui + installer-row.ui dll-override-entry.ui env-var-entry.ui component-entry-row.ui diff --git a/bottles/frontend/ui/installer-entry.blp b/bottles/frontend/ui/installer-row.blp similarity index 96% rename from bottles/frontend/ui/installer-entry.blp rename to bottles/frontend/ui/installer-row.blp index 3af12b0f924..50f530d4312 100644 --- a/bottles/frontend/ui/installer-entry.blp +++ b/bottles/frontend/ui/installer-row.blp @@ -29,7 +29,7 @@ Popover pop_actions { } } -template $InstallerEntry: Adw.ActionRow { +template $InstallerRow: Adw.ActionRow { activatable-widget: btn_install; title: _("Installer name"); subtitle: _("Installer description"); diff --git a/bottles/frontend/ui/meson.build b/bottles/frontend/ui/meson.build index 55a58636708..293af4d986a 100644 --- a/bottles/frontend/ui/meson.build +++ b/bottles/frontend/ui/meson.build @@ -38,7 +38,7 @@ blueprints = custom_target('blueprints', 'exclusion-pattern-row.blp', 'importer-row.blp', 'importer-view.blp', - 'installer-entry.blp', + 'installer-row.blp', 'library-entry.blp', 'library.blp', 'bottle-row.blp', diff --git a/bottles/frontend/views/details_installers_view.py b/bottles/frontend/views/details_installers_view.py index 16513653cf1..cb74fd620d5 100644 --- a/bottles/frontend/views/details_installers_view.py +++ b/bottles/frontend/views/details_installers_view.py @@ -23,7 +23,7 @@ from bottles.backend.utils.threading import RunAsync from bottles.frontend.utils.common import open_doc_url -from bottles.frontend.widgets.installer import InstallerEntry +from bottles.frontend.widgets.installer_row import InstallerRow @Gtk.Template(resource_path="/com/usebottles/bottles/details-installers-view.ui") @@ -93,7 +93,7 @@ def update(self, widget=False, config=None): self.list_installers.set_sensitive(False) def new_installer(_installer): - entry = InstallerEntry( + entry = InstallerRow( window=self.window, config=self.config, installer=_installer ) self.list_installers.append(entry) diff --git a/bottles/frontend/widgets/installer.py b/bottles/frontend/widgets/installer_row.py similarity index 94% rename from bottles/frontend/widgets/installer.py rename to bottles/frontend/widgets/installer_row.py index cc36452cfd7..cf001399cba 100644 --- a/bottles/frontend/widgets/installer.py +++ b/bottles/frontend/widgets/installer_row.py @@ -1,6 +1,6 @@ -# installer.py +# installer_row.py # -# Copyright 2022 brombinmirko +# Copyright 2025 The Bottles Contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -23,9 +23,9 @@ from bottles.frontend.windows.installer import InstallerDialog -@Gtk.Template(resource_path="/com/usebottles/bottles/installer-entry.ui") -class InstallerEntry(Adw.ActionRow): - __gtype_name__ = "InstallerEntry" +@Gtk.Template(resource_path="/com/usebottles/bottles/installer-row.ui") +class InstallerRow(Adw.ActionRow): + __gtype_name__ = "InstallerRow" # region Widgets btn_install = Gtk.Template.Child() diff --git a/bottles/frontend/widgets/meson.build b/bottles/frontend/widgets/meson.build index 69ce2cd338c..941db29d822 100644 --- a/bottles/frontend/widgets/meson.build +++ b/bottles/frontend/widgets/meson.build @@ -6,7 +6,7 @@ bottles_sources = [ 'dependency_entry_row.py', 'executable.py', 'importer_row.py', - 'installer.py', + 'installer_row.py', 'program.py', 'state.py', 'component_entry_row.py', diff --git a/po/POTFILES b/po/POTFILES index 8ea61011d19..870f69e9e83 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -39,7 +39,7 @@ bottles/frontend/ui/env-var-entry.blp bottles/frontend/ui/exclusion-pattern-row.blp bottles/frontend/ui/importer-row.blp bottles/frontend/ui/importer-view.blp -bottles/frontend/ui/installer-entry.blp +bottles/frontend/ui/installer-row.blp bottles/frontend/ui/library-entry.blp bottles/frontend/ui/library.blp bottles/frontend/ui/bottle-row.blp @@ -66,7 +66,7 @@ bottles/frontend/views/preferences.py bottles/frontend/widgets/component.py bottles/frontend/widgets/dependency.py bottles/frontend/widgets/importer_row.py -bottles/frontend/widgets/installer.py +bottles/frontend/widgets/installer_row.py bottles/frontend/widgets/library.py bottles/frontend/widgets/program.py bottles/frontend/widgets/state.py From f2a84b40b330968f5b32cb0b17b289fb6e5a5fe1 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Sun, 12 Jan 2025 19:06:17 -0500 Subject: [PATCH 032/146] library-view: Rename files and add to POTFILES --- bottles/frontend/ui/bottles.gresource.xml | 2 +- bottles/frontend/ui/{library.blp => library-view.blp} | 0 bottles/frontend/ui/meson.build | 2 +- bottles/frontend/views/{library.py => library_view.py} | 6 +++--- bottles/frontend/views/meson.build | 2 +- bottles/frontend/windows/window.py | 2 +- po/POTFILES | 3 ++- 7 files changed, 9 insertions(+), 8 deletions(-) rename bottles/frontend/ui/{library.blp => library-view.blp} (100%) rename bottles/frontend/views/{library.py => library_view.py} (95%) diff --git a/bottles/frontend/ui/bottles.gresource.xml b/bottles/frontend/ui/bottles.gresource.xml index ad2fab6d5fe..717ad68aa3a 100644 --- a/bottles/frontend/ui/bottles.gresource.xml +++ b/bottles/frontend/ui/bottles.gresource.xml @@ -32,7 +32,7 @@ details-task-manager-view.ui preferences.ui importer-view.ui - library.ui + library-view.ui dialog-launch-options.ui dll-overrides-dialog.ui dialog-env-vars.ui diff --git a/bottles/frontend/ui/library.blp b/bottles/frontend/ui/library-view.blp similarity index 100% rename from bottles/frontend/ui/library.blp rename to bottles/frontend/ui/library-view.blp diff --git a/bottles/frontend/ui/meson.build b/bottles/frontend/ui/meson.build index 293af4d986a..39db4c2cacc 100644 --- a/bottles/frontend/ui/meson.build +++ b/bottles/frontend/ui/meson.build @@ -40,7 +40,7 @@ blueprints = custom_target('blueprints', 'importer-view.blp', 'installer-row.blp', 'library-entry.blp', - 'library.blp', + 'library-view.blp', 'bottle-row.blp', 'list.blp', 'loading.blp', diff --git a/bottles/frontend/views/library.py b/bottles/frontend/views/library_view.py similarity index 95% rename from bottles/frontend/views/library.py rename to bottles/frontend/views/library_view.py index bebea15a104..45cbf5ad80f 100644 --- a/bottles/frontend/views/library.py +++ b/bottles/frontend/views/library_view.py @@ -1,6 +1,6 @@ -# library.py +# library_view.py # -# Copyright 2022 brombinmirko +# Copyright 2025 The Bottles Contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -25,7 +25,7 @@ from bottles.frontend.widgets.library import LibraryEntry -@Gtk.Template(resource_path="/com/usebottles/bottles/library.ui") +@Gtk.Template(resource_path="/com/usebottles/bottles/library-view.ui") class LibraryView(Adw.Bin): __gtype_name__ = "LibraryView" diff --git a/bottles/frontend/views/meson.build b/bottles/frontend/views/meson.build index 38ec9d5fb79..b8511464655 100644 --- a/bottles/frontend/views/meson.build +++ b/bottles/frontend/views/meson.build @@ -5,7 +5,7 @@ bottles_sources = [ '__init__.py', 'new_bottle_dialog.py', 'list.py', - 'library.py', + 'library_view.py', 'bottle_details_view.py', 'preferences.py', 'importer_view.py', diff --git a/bottles/frontend/windows/window.py b/bottles/frontend/windows/window.py index 17338878614..eb33db17df5 100644 --- a/bottles/frontend/windows/window.py +++ b/bottles/frontend/windows/window.py @@ -38,7 +38,7 @@ from bottles.frontend.utils.gtk import GtkUtils from bottles.frontend.views.bottle_details_view import BottleDetailsView from bottles.frontend.views.importer_view import ImporterView -from bottles.frontend.views.library import LibraryView +from bottles.frontend.views.library_view import LibraryView from bottles.frontend.views.list import BottleView from bottles.frontend.views.loading import LoadingView from bottles.frontend.views.new_bottle_dialog import NewBottleDialog diff --git a/po/POTFILES b/po/POTFILES index 870f69e9e83..88e9e85dd25 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -41,7 +41,7 @@ bottles/frontend/ui/importer-row.blp bottles/frontend/ui/importer-view.blp bottles/frontend/ui/installer-row.blp bottles/frontend/ui/library-entry.blp -bottles/frontend/ui/library.blp +bottles/frontend/ui/library-view.blp bottles/frontend/ui/bottle-row.blp bottles/frontend/ui/list.blp bottles/frontend/ui/loading.blp @@ -63,6 +63,7 @@ bottles/frontend/views/list.py bottles/frontend/views/loading.py bottles/frontend/views/new_bottle_dialog.py bottles/frontend/views/preferences.py +bottles/frontend/views/library_view.py bottles/frontend/widgets/component.py bottles/frontend/widgets/dependency.py bottles/frontend/widgets/importer_row.py From 555898422ef98d7d27a973a3ab32e9d173104c19 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Sun, 12 Jan 2025 19:10:41 -0500 Subject: [PATCH 033/146] bottles-list-view: Rename files and class name --- .../frontend/ui/{list.blp => bottles-list-view.blp} | 2 +- bottles/frontend/ui/bottles.gresource.xml | 2 +- bottles/frontend/ui/meson.build | 2 +- .../frontend/views/{list.py => bottles_list_view.py} | 10 +++++----- bottles/frontend/views/meson.build | 2 +- bottles/frontend/windows/window.py | 4 ++-- po/POTFILES | 4 ++-- 7 files changed, 13 insertions(+), 13 deletions(-) rename bottles/frontend/ui/{list.blp => bottles-list-view.blp} (97%) rename bottles/frontend/views/{list.py => bottles_list_view.py} (97%) diff --git a/bottles/frontend/ui/list.blp b/bottles/frontend/ui/bottles-list-view.blp similarity index 97% rename from bottles/frontend/ui/list.blp rename to bottles/frontend/ui/bottles-list-view.blp index 104c27dd510..299ca52141d 100644 --- a/bottles/frontend/ui/list.blp +++ b/bottles/frontend/ui/bottles-list-view.blp @@ -1,7 +1,7 @@ using Gtk 4.0; using Adw 1; -template $BottleView: Adw.Bin { +template $BottlesListView: Adw.Bin { ScrolledWindow { Box { hexpand: true; diff --git a/bottles/frontend/ui/bottles.gresource.xml b/bottles/frontend/ui/bottles.gresource.xml index 717ad68aa3a..753c269ba24 100644 --- a/bottles/frontend/ui/bottles.gresource.xml +++ b/bottles/frontend/ui/bottles.gresource.xml @@ -6,7 +6,7 @@ help-overlay.ui window.ui new-bottle-dialog.ui - list.ui + bottles-list-view.ui loading.ui bottle-row.ui check-row.ui diff --git a/bottles/frontend/ui/meson.build b/bottles/frontend/ui/meson.build index 39db4c2cacc..fac40168d24 100644 --- a/bottles/frontend/ui/meson.build +++ b/bottles/frontend/ui/meson.build @@ -42,7 +42,7 @@ blueprints = custom_target('blueprints', 'library-entry.blp', 'library-view.blp', 'bottle-row.blp', - 'list.blp', + 'bottles-list-view.blp', 'loading.blp', 'local-resource-entry.blp', 'new-bottle-dialog.blp', diff --git a/bottles/frontend/views/list.py b/bottles/frontend/views/bottles_list_view.py similarity index 97% rename from bottles/frontend/views/list.py rename to bottles/frontend/views/bottles_list_view.py index 24fb30b9e95..75738fd48d3 100644 --- a/bottles/frontend/views/list.py +++ b/bottles/frontend/views/bottles_list_view.py @@ -1,6 +1,6 @@ -# list.py +# bottles_list_view.py # -# Copyright 2022 brombinmirko +# Copyright 2025 The Bottles Contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -123,9 +123,9 @@ def disable(self): self.set_visible(False) -@Gtk.Template(resource_path="/com/usebottles/bottles/list.ui") -class BottleView(Adw.Bin): - __gtype_name__ = "BottleView" +@Gtk.Template(resource_path="/com/usebottles/bottles/bottles-list-view.ui") +class BottlesListView(Adw.Bin): + __gtype_name__ = "BottlesListView" __bottles = {} # region Widgets diff --git a/bottles/frontend/views/meson.build b/bottles/frontend/views/meson.build index b8511464655..281e9a4cea0 100644 --- a/bottles/frontend/views/meson.build +++ b/bottles/frontend/views/meson.build @@ -4,7 +4,7 @@ viewsdir = join_paths(pkgdatadir, 'bottles/frontend/views') bottles_sources = [ '__init__.py', 'new_bottle_dialog.py', - 'list.py', + 'bottles_list_view.py', 'library_view.py', 'bottle_details_view.py', 'preferences.py', diff --git a/bottles/frontend/windows/window.py b/bottles/frontend/windows/window.py index eb33db17df5..dfe90807162 100644 --- a/bottles/frontend/windows/window.py +++ b/bottles/frontend/windows/window.py @@ -39,7 +39,7 @@ from bottles.frontend.views.bottle_details_view import BottleDetailsView from bottles.frontend.views.importer_view import ImporterView from bottles.frontend.views.library_view import LibraryView -from bottles.frontend.views.list import BottleView +from bottles.frontend.views.bottles_list_view import BottlesListView from bottles.frontend.views.loading import LoadingView from bottles.frontend.views.new_bottle_dialog import NewBottleDialog from bottles.frontend.views.preferences import PreferencesWindow @@ -221,7 +221,7 @@ def set_manager(result: Manager, error=None): # Pages self.page_details = BottleDetailsView(self) - self.page_list = BottleView(self, arg_bottle=self.arg_bottle) + self.page_list = BottlesListView(self, arg_bottle=self.arg_bottle) self.page_importer = ImporterView(self) self.page_library = LibraryView(self) diff --git a/po/POTFILES b/po/POTFILES index 88e9e85dd25..95f255b4d7f 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -43,7 +43,7 @@ bottles/frontend/ui/installer-row.blp bottles/frontend/ui/library-entry.blp bottles/frontend/ui/library-view.blp bottles/frontend/ui/bottle-row.blp -bottles/frontend/ui/list.blp +bottles/frontend/ui/bottles-list-view.blp bottles/frontend/ui/loading.blp bottles/frontend/ui/local-resource-entry.blp bottles/frontend/ui/new-bottle-dialog.blp @@ -59,7 +59,7 @@ bottles/frontend/views/details_preferences_page.py bottles/frontend/views/details_versioning_page.py bottles/frontend/views/bottle_details_view.py bottles/frontend/views/importer_view.py -bottles/frontend/views/list.py +bottles/frontend/views/bottles_list_view.py bottles/frontend/views/loading.py bottles/frontend/views/new_bottle_dialog.py bottles/frontend/views/preferences.py From aa2a59d00fa978a729e374f5daf2895077eb9f6b Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Sun, 12 Jan 2025 19:13:11 -0500 Subject: [PATCH 034/146] loading-view: Rename files --- bottles/frontend/ui/bottles.gresource.xml | 2 +- bottles/frontend/ui/{loading.blp => loading-view.blp} | 0 bottles/frontend/ui/meson.build | 2 +- bottles/frontend/views/{loading.py => loading_view.py} | 6 +++--- bottles/frontend/views/meson.build | 2 +- bottles/frontend/windows/window.py | 2 +- po/POTFILES | 4 ++-- 7 files changed, 9 insertions(+), 9 deletions(-) rename bottles/frontend/ui/{loading.blp => loading-view.blp} (100%) rename bottles/frontend/views/{loading.py => loading_view.py} (93%) diff --git a/bottles/frontend/ui/bottles.gresource.xml b/bottles/frontend/ui/bottles.gresource.xml index 753c269ba24..fdfaa1d60d0 100644 --- a/bottles/frontend/ui/bottles.gresource.xml +++ b/bottles/frontend/ui/bottles.gresource.xml @@ -7,7 +7,7 @@ window.ui new-bottle-dialog.ui bottles-list-view.ui - loading.ui + loading-view.ui bottle-row.ui check-row.ui task-entry.ui diff --git a/bottles/frontend/ui/loading.blp b/bottles/frontend/ui/loading-view.blp similarity index 100% rename from bottles/frontend/ui/loading.blp rename to bottles/frontend/ui/loading-view.blp diff --git a/bottles/frontend/ui/meson.build b/bottles/frontend/ui/meson.build index fac40168d24..1d2091bee85 100644 --- a/bottles/frontend/ui/meson.build +++ b/bottles/frontend/ui/meson.build @@ -43,7 +43,7 @@ blueprints = custom_target('blueprints', 'library-view.blp', 'bottle-row.blp', 'bottles-list-view.blp', - 'loading.blp', + 'loading-view.blp', 'local-resource-entry.blp', 'new-bottle-dialog.blp', 'onboard.blp', diff --git a/bottles/frontend/views/loading.py b/bottles/frontend/views/loading_view.py similarity index 93% rename from bottles/frontend/views/loading.py rename to bottles/frontend/views/loading_view.py index 7d165eb3f49..36c44d585f2 100644 --- a/bottles/frontend/views/loading.py +++ b/bottles/frontend/views/loading_view.py @@ -1,6 +1,6 @@ -# loading.py +# loading_view.py # -# Copyright 2022 brombinmirko +# Copyright 2025 The Bottles Contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -25,7 +25,7 @@ from bottles.frontend.params import APP_ID -@Gtk.Template(resource_path="/com/usebottles/bottles/loading.ui") +@Gtk.Template(resource_path="/com/usebottles/bottles/loading-view.ui") class LoadingView(Adw.Bin): __gtype_name__ = "LoadingView" __fetched = 0 diff --git a/bottles/frontend/views/meson.build b/bottles/frontend/views/meson.build index 281e9a4cea0..f856cda06ab 100644 --- a/bottles/frontend/views/meson.build +++ b/bottles/frontend/views/meson.build @@ -9,7 +9,7 @@ bottles_sources = [ 'bottle_details_view.py', 'preferences.py', 'importer_view.py', - 'loading.py', + 'loading_view.py', 'bottle_details_page.py', 'details_installers_view.py', diff --git a/bottles/frontend/windows/window.py b/bottles/frontend/windows/window.py index dfe90807162..4dc23d83b0c 100644 --- a/bottles/frontend/windows/window.py +++ b/bottles/frontend/windows/window.py @@ -40,7 +40,7 @@ from bottles.frontend.views.importer_view import ImporterView from bottles.frontend.views.library_view import LibraryView from bottles.frontend.views.bottles_list_view import BottlesListView -from bottles.frontend.views.loading import LoadingView +from bottles.frontend.views.loading_view import LoadingView from bottles.frontend.views.new_bottle_dialog import NewBottleDialog from bottles.frontend.views.preferences import PreferencesWindow from bottles.frontend.windows.crash_report_dialog import CrashReportDialog diff --git a/po/POTFILES b/po/POTFILES index 95f255b4d7f..fcf27c715d2 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -44,7 +44,7 @@ bottles/frontend/ui/library-entry.blp bottles/frontend/ui/library-view.blp bottles/frontend/ui/bottle-row.blp bottles/frontend/ui/bottles-list-view.blp -bottles/frontend/ui/loading.blp +bottles/frontend/ui/loading-view.blp bottles/frontend/ui/local-resource-entry.blp bottles/frontend/ui/new-bottle-dialog.blp bottles/frontend/ui/onboard.blp @@ -60,7 +60,7 @@ bottles/frontend/views/details_versioning_page.py bottles/frontend/views/bottle_details_view.py bottles/frontend/views/importer_view.py bottles/frontend/views/bottles_list_view.py -bottles/frontend/views/loading.py +bottles/frontend/views/loading_view.py bottles/frontend/views/new_bottle_dialog.py bottles/frontend/views/preferences.py bottles/frontend/views/library_view.py From c5bbdbede7161f4f8b74707ce3f75f00db133635 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Sun, 12 Jan 2025 19:18:51 -0500 Subject: [PATCH 035/146] local-resource-row: Rename class name --- bottles/frontend/ui/bottles.gresource.xml | 2 +- .../{local-resource-entry.blp => local-resource-row.blp} | 2 +- bottles/frontend/ui/meson.build | 2 +- bottles/frontend/windows/installer.py | 8 ++++---- po/POTFILES | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) rename bottles/frontend/ui/{local-resource-entry.blp => local-resource-row.blp} (83%) diff --git a/bottles/frontend/ui/bottles.gresource.xml b/bottles/frontend/ui/bottles.gresource.xml index fdfaa1d60d0..bb01ac283be 100644 --- a/bottles/frontend/ui/bottles.gresource.xml +++ b/bottles/frontend/ui/bottles.gresource.xml @@ -21,7 +21,7 @@ component-entry-row.ui drive-entry.ui library-entry.ui - local-resource-entry.ui + local-resource-row.ui exclusion-pattern-row.ui bottle-details-view.ui bottle-details-page.ui diff --git a/bottles/frontend/ui/local-resource-entry.blp b/bottles/frontend/ui/local-resource-row.blp similarity index 83% rename from bottles/frontend/ui/local-resource-entry.blp rename to bottles/frontend/ui/local-resource-row.blp index 9af5a3ba341..7ee81f68453 100644 --- a/bottles/frontend/ui/local-resource-entry.blp +++ b/bottles/frontend/ui/local-resource-row.blp @@ -1,7 +1,7 @@ using Gtk 4.0; using Adw 1; -template $LocalResourceEntry: Adw.ActionRow { +template $LocalResourceRow: Adw.ActionRow { subtitle: _("This resource is missing."); Button btn_path { diff --git a/bottles/frontend/ui/meson.build b/bottles/frontend/ui/meson.build index 1d2091bee85..b7c2413113d 100644 --- a/bottles/frontend/ui/meson.build +++ b/bottles/frontend/ui/meson.build @@ -44,7 +44,7 @@ blueprints = custom_target('blueprints', 'bottle-row.blp', 'bottles-list-view.blp', 'loading-view.blp', - 'local-resource-entry.blp', + 'local-resource-row.blp', 'new-bottle-dialog.blp', 'onboard.blp', 'preferences.blp', diff --git a/bottles/frontend/windows/installer.py b/bottles/frontend/windows/installer.py index 23343c9a2d1..dc520466e67 100644 --- a/bottles/frontend/windows/installer.py +++ b/bottles/frontend/windows/installer.py @@ -24,9 +24,9 @@ from bottles.frontend.utils.gtk import GtkUtils -@Gtk.Template(resource_path="/com/usebottles/bottles/local-resource-entry.ui") -class LocalResourceEntry(Adw.ActionRow): - __gtype_name__ = "LocalResourceEntry" +@Gtk.Template(resource_path="/com/usebottles/bottles/local-resource-row.ui") +class LocalResourceRow(Adw.ActionRow): + __gtype_name__ = "LocalResourceRow" # region Widgets btn_path = Gtk.Template.Child() @@ -157,7 +157,7 @@ def __check_resources(self, *_args): return for resource in self.__local_resources: - _entry = LocalResourceEntry(self, resource) + _entry = LocalResourceRow(self, resource) GLib.idle_add(self.group_resources.add, _entry) self.btn_proceed.set_visible(True) diff --git a/po/POTFILES b/po/POTFILES index fcf27c715d2..1394ae849ca 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -45,7 +45,7 @@ bottles/frontend/ui/library-view.blp bottles/frontend/ui/bottle-row.blp bottles/frontend/ui/bottles-list-view.blp bottles/frontend/ui/loading-view.blp -bottles/frontend/ui/local-resource-entry.blp +bottles/frontend/ui/local-resource-row.blp bottles/frontend/ui/new-bottle-dialog.blp bottles/frontend/ui/onboard.blp bottles/frontend/ui/preferences.blp From c8f8135e7a009d938973b9ee742ad0837eaa3365 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Sun, 12 Jan 2025 19:30:32 -0500 Subject: [PATCH 036/146] onboard-dialog: Rename files --- bottles/frontend/ui/bottles.gresource.xml | 2 +- bottles/frontend/ui/meson.build | 2 +- bottles/frontend/ui/{onboard.blp => onboard-dialog.blp} | 0 bottles/frontend/windows/meson.build | 2 +- bottles/frontend/windows/{onboard.py => onboard_dialog.py} | 6 +++--- bottles/frontend/windows/window.py | 2 +- po/POTFILES | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) rename bottles/frontend/ui/{onboard.blp => onboard-dialog.blp} (100%) rename bottles/frontend/windows/{onboard.py => onboard_dialog.py} (97%) diff --git a/bottles/frontend/ui/bottles.gresource.xml b/bottles/frontend/ui/bottles.gresource.xml index bb01ac283be..4c902199c27 100644 --- a/bottles/frontend/ui/bottles.gresource.xml +++ b/bottles/frontend/ui/bottles.gresource.xml @@ -54,6 +54,6 @@ exclusion-patterns-dialog.ui dialog-upgrade-versioning.ui dialog-vmtouch.ui - onboard.ui + onboard-dialog.ui diff --git a/bottles/frontend/ui/meson.build b/bottles/frontend/ui/meson.build index b7c2413113d..52e509dffda 100644 --- a/bottles/frontend/ui/meson.build +++ b/bottles/frontend/ui/meson.build @@ -46,7 +46,7 @@ blueprints = custom_target('blueprints', 'loading-view.blp', 'local-resource-row.blp', 'new-bottle-dialog.blp', - 'onboard.blp', + 'onboard-dialog.blp', 'preferences.blp', 'program-entry.blp', 'state-entry.blp', diff --git a/bottles/frontend/ui/onboard.blp b/bottles/frontend/ui/onboard-dialog.blp similarity index 100% rename from bottles/frontend/ui/onboard.blp rename to bottles/frontend/ui/onboard-dialog.blp diff --git a/bottles/frontend/windows/meson.build b/bottles/frontend/windows/meson.build index 30614edb58c..843854605d7 100644 --- a/bottles/frontend/windows/meson.build +++ b/bottles/frontend/windows/meson.build @@ -9,7 +9,7 @@ bottles_sources = [ 'envvars.py', 'generic.py', 'launchoptions.py', - 'onboard.py', + 'onboard_dialog.py', 'rename.py', 'drives_dialog.py', 'gamescope_dialog.py', diff --git a/bottles/frontend/windows/onboard.py b/bottles/frontend/windows/onboard_dialog.py similarity index 97% rename from bottles/frontend/windows/onboard.py rename to bottles/frontend/windows/onboard_dialog.py index 7a56ef71dc7..076e36a8124 100644 --- a/bottles/frontend/windows/onboard.py +++ b/bottles/frontend/windows/onboard_dialog.py @@ -1,6 +1,6 @@ -# onboard.py +# onboard_dialog.py # -# Copyright 2022 brombinmirko +# Copyright 2025 The Bottles Contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -24,7 +24,7 @@ from bottles.frontend.utils.gtk import GtkUtils -@Gtk.Template(resource_path="/com/usebottles/bottles/onboard.ui") +@Gtk.Template(resource_path="/com/usebottles/bottles/onboard-dialog.ui") class OnboardDialog(Adw.Window): __gtype_name__ = "OnboardDialog" __installing = False diff --git a/bottles/frontend/windows/window.py b/bottles/frontend/windows/window.py index 4dc23d83b0c..eb85e427b99 100644 --- a/bottles/frontend/windows/window.py +++ b/bottles/frontend/windows/window.py @@ -45,7 +45,7 @@ from bottles.frontend.views.preferences import PreferencesWindow from bottles.frontend.windows.crash_report_dialog import CrashReportDialog from bottles.frontend.windows.dependencies_check_dialog import DependenciesCheckDialog -from bottles.frontend.windows.onboard import OnboardDialog +from bottles.frontend.windows.onboard_dialog import OnboardDialog logging = Logger() diff --git a/po/POTFILES b/po/POTFILES index 1394ae849ca..5c5d3e604bc 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -47,7 +47,7 @@ bottles/frontend/ui/bottles-list-view.blp bottles/frontend/ui/loading-view.blp bottles/frontend/ui/local-resource-row.blp bottles/frontend/ui/new-bottle-dialog.blp -bottles/frontend/ui/onboard.blp +bottles/frontend/ui/onboard-dialog.blp bottles/frontend/ui/preferences.blp bottles/frontend/ui/program-entry.blp bottles/frontend/ui/state-entry.blp From ea587df0c628370fa1280e537f03b4f10edaca35 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Sun, 12 Jan 2025 19:45:21 -0500 Subject: [PATCH 037/146] program-row: Rename files and class name --- bottles/frontend/ui/bottles.gresource.xml | 2 +- bottles/frontend/ui/meson.build | 2 +- .../frontend/ui/{program-entry.blp => program-row.blp} | 2 +- bottles/frontend/views/bottle_details_page.py | 4 ++-- bottles/frontend/widgets/meson.build | 2 +- .../frontend/widgets/{program.py => program_row.py} | 10 +++++----- po/POTFILES | 4 ++-- 7 files changed, 13 insertions(+), 13 deletions(-) rename bottles/frontend/ui/{program-entry.blp => program-row.blp} (98%) rename bottles/frontend/widgets/{program.py => program_row.py} (98%) diff --git a/bottles/frontend/ui/bottles.gresource.xml b/bottles/frontend/ui/bottles.gresource.xml index 4c902199c27..b2e72e698c3 100644 --- a/bottles/frontend/ui/bottles.gresource.xml +++ b/bottles/frontend/ui/bottles.gresource.xml @@ -12,7 +12,7 @@ check-row.ui task-entry.ui dependency-entry-row.ui - program-entry.ui + program-row.ui importer-row.ui state-entry.ui installer-row.ui diff --git a/bottles/frontend/ui/meson.build b/bottles/frontend/ui/meson.build index 52e509dffda..893bf673074 100644 --- a/bottles/frontend/ui/meson.build +++ b/bottles/frontend/ui/meson.build @@ -48,7 +48,7 @@ blueprints = custom_target('blueprints', 'new-bottle-dialog.blp', 'onboard-dialog.blp', 'preferences.blp', - 'program-entry.blp', + 'program-row.blp', 'state-entry.blp', 'task-entry.blp', 'window.blp', diff --git a/bottles/frontend/ui/program-entry.blp b/bottles/frontend/ui/program-row.blp similarity index 98% rename from bottles/frontend/ui/program-entry.blp rename to bottles/frontend/ui/program-row.blp index 9bb02f4ec2c..7c51a6e95bf 100644 --- a/bottles/frontend/ui/program-entry.blp +++ b/bottles/frontend/ui/program-row.blp @@ -77,7 +77,7 @@ Popover pop_actions { } } -template $ProgramEntry: Adw.ActionRow { +template $ProgramRow: Adw.ActionRow { title: _("Program name"); Box { diff --git a/bottles/frontend/views/bottle_details_page.py b/bottles/frontend/views/bottle_details_page.py index 62f237fc4bf..39b39065bfe 100644 --- a/bottles/frontend/views/bottle_details_page.py +++ b/bottles/frontend/views/bottle_details_page.py @@ -41,7 +41,7 @@ from bottles.frontend.utils.common import open_doc_url from bottles.frontend.utils.filters import add_executable_filters, add_all_filters from bottles.frontend.utils.gtk import GtkUtils -from bottles.frontend.widgets.program import ProgramEntry +from bottles.frontend.widgets.program_row import ProgramRow from bottles.frontend.windows.duplicate_dialog import DuplicateDialog from bottles.frontend.windows.upgradeversioning import UpgradeVersioningDialog @@ -308,7 +308,7 @@ def new_program( check_boot = wineserver_status self.add_program( - ProgramEntry( + ProgramRow( self.window, self.config, _program, diff --git a/bottles/frontend/widgets/meson.build b/bottles/frontend/widgets/meson.build index 941db29d822..21a7a6cb5f3 100644 --- a/bottles/frontend/widgets/meson.build +++ b/bottles/frontend/widgets/meson.build @@ -7,7 +7,7 @@ bottles_sources = [ 'executable.py', 'importer_row.py', 'installer_row.py', - 'program.py', + 'program_row.py', 'state.py', 'component_entry_row.py', 'library.py', diff --git a/bottles/frontend/widgets/program.py b/bottles/frontend/widgets/program_row.py similarity index 98% rename from bottles/frontend/widgets/program.py rename to bottles/frontend/widgets/program_row.py index 2b0e43b382a..3158d02f12f 100644 --- a/bottles/frontend/widgets/program.py +++ b/bottles/frontend/widgets/program_row.py @@ -1,6 +1,6 @@ -# program.py +# program_row.py # -# Copyright 2022 brombinmirko +# Copyright 2025 The Bottles Contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -34,9 +34,9 @@ # noinspection PyUnusedLocal -@Gtk.Template(resource_path="/com/usebottles/bottles/program-entry.ui") -class ProgramEntry(Adw.ActionRow): - __gtype_name__ = "ProgramEntry" +@Gtk.Template(resource_path="/com/usebottles/bottles/program-row.ui") +class ProgramRow(Adw.ActionRow): + __gtype_name__ = "ProgramRow" # region Widgets btn_menu = Gtk.Template.Child() diff --git a/po/POTFILES b/po/POTFILES index 5c5d3e604bc..52f91e1388c 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -49,7 +49,7 @@ bottles/frontend/ui/local-resource-row.blp bottles/frontend/ui/new-bottle-dialog.blp bottles/frontend/ui/onboard-dialog.blp bottles/frontend/ui/preferences.blp -bottles/frontend/ui/program-entry.blp +bottles/frontend/ui/program-row.blp bottles/frontend/ui/state-entry.blp bottles/frontend/ui/task-entry.blp bottles/frontend/ui/window.blp @@ -69,7 +69,7 @@ bottles/frontend/widgets/dependency.py bottles/frontend/widgets/importer_row.py bottles/frontend/widgets/installer_row.py bottles/frontend/widgets/library.py -bottles/frontend/widgets/program.py +bottles/frontend/widgets/program_row.py bottles/frontend/widgets/state.py bottles/frontend/windows/crash_report_dialog.py bottles/frontend/windows/display_dialog.py From 68f6b26669af301ec66c1693d428af71252939ce Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Sun, 12 Jan 2025 19:48:10 -0500 Subject: [PATCH 038/146] state-row: Rename files and class name --- bottles/frontend/ui/bottles.gresource.xml | 2 +- bottles/frontend/ui/meson.build | 2 +- bottles/frontend/ui/{state-entry.blp => state-row.blp} | 2 +- bottles/frontend/views/details_versioning_page.py | 4 ++-- bottles/frontend/widgets/meson.build | 2 +- bottles/frontend/widgets/{state.py => state_row.py} | 10 +++++----- po/POTFILES | 4 ++-- 7 files changed, 13 insertions(+), 13 deletions(-) rename bottles/frontend/ui/{state-entry.blp => state-row.blp} (91%) rename bottles/frontend/widgets/{state.py => state_row.py} (95%) diff --git a/bottles/frontend/ui/bottles.gresource.xml b/bottles/frontend/ui/bottles.gresource.xml index b2e72e698c3..9a9e3edc847 100644 --- a/bottles/frontend/ui/bottles.gresource.xml +++ b/bottles/frontend/ui/bottles.gresource.xml @@ -14,7 +14,7 @@ dependency-entry-row.ui program-row.ui importer-row.ui - state-entry.ui + state-row.ui installer-row.ui dll-override-entry.ui env-var-entry.ui diff --git a/bottles/frontend/ui/meson.build b/bottles/frontend/ui/meson.build index 893bf673074..66057a72784 100644 --- a/bottles/frontend/ui/meson.build +++ b/bottles/frontend/ui/meson.build @@ -49,7 +49,7 @@ blueprints = custom_target('blueprints', 'onboard-dialog.blp', 'preferences.blp', 'program-row.blp', - 'state-entry.blp', + 'state-row.blp', 'task-entry.blp', 'window.blp', 'details-preferences-page.blp', diff --git a/bottles/frontend/ui/state-entry.blp b/bottles/frontend/ui/state-row.blp similarity index 91% rename from bottles/frontend/ui/state-entry.blp rename to bottles/frontend/ui/state-row.blp index ef3efee0846..8358e50282e 100644 --- a/bottles/frontend/ui/state-entry.blp +++ b/bottles/frontend/ui/state-row.blp @@ -1,7 +1,7 @@ using Gtk 4.0; using Adw 1; -template $StateEntry: Adw.ActionRow { +template $StateRow: Adw.ActionRow { activatable-widget: btn_restore; /* Translators: id as identification */ diff --git a/bottles/frontend/views/details_versioning_page.py b/bottles/frontend/views/details_versioning_page.py index 946a6206843..661852d3f9c 100644 --- a/bottles/frontend/views/details_versioning_page.py +++ b/bottles/frontend/views/details_versioning_page.py @@ -24,7 +24,7 @@ from bottles.backend.utils.threading import RunAsync from bottles.frontend.utils.common import open_doc_url from bottles.frontend.utils.gtk import GtkUtils -from bottles.frontend.widgets.state import StateEntry +from bottles.frontend.widgets.state_row import StateRow @Gtk.Template(resource_path="/com/usebottles/bottles/details-versioning-page.ui") @@ -92,7 +92,7 @@ def update(self, widget=None, config=None, states=None, active=0): ) def new_state(_state, active): - entry = StateEntry( + entry = StateRow( parent=self, config=self.config, state=_state, active=active ) self.__registry.append(entry) diff --git a/bottles/frontend/widgets/meson.build b/bottles/frontend/widgets/meson.build index 21a7a6cb5f3..db12efc56d0 100644 --- a/bottles/frontend/widgets/meson.build +++ b/bottles/frontend/widgets/meson.build @@ -8,7 +8,7 @@ bottles_sources = [ 'importer_row.py', 'installer_row.py', 'program_row.py', - 'state.py', + 'state_row.py', 'component_entry_row.py', 'library.py', ] diff --git a/bottles/frontend/widgets/state.py b/bottles/frontend/widgets/state_row.py similarity index 95% rename from bottles/frontend/widgets/state.py rename to bottles/frontend/widgets/state_row.py index ee016c3960a..6f3c0f26faf 100644 --- a/bottles/frontend/widgets/state.py +++ b/bottles/frontend/widgets/state_row.py @@ -1,6 +1,6 @@ -# state.py +# state_row.py # -# Copyright 2022 brombinmirko +# Copyright 2025 The Bottles Contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -24,9 +24,9 @@ from bottles.frontend.utils.gtk import GtkUtils -@Gtk.Template(resource_path="/com/usebottles/bottles/state-entry.ui") -class StateEntry(Adw.ActionRow): - __gtype_name__ = "StateEntry" +@Gtk.Template(resource_path="/com/usebottles/bottles/state-row.ui") +class StateRow(Adw.ActionRow): + __gtype_name__ = "StateRow" # region Widgets btn_restore = Gtk.Template.Child() diff --git a/po/POTFILES b/po/POTFILES index 52f91e1388c..f1e3400fdeb 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -50,7 +50,7 @@ bottles/frontend/ui/new-bottle-dialog.blp bottles/frontend/ui/onboard-dialog.blp bottles/frontend/ui/preferences.blp bottles/frontend/ui/program-row.blp -bottles/frontend/ui/state-entry.blp +bottles/frontend/ui/state-row.blp bottles/frontend/ui/task-entry.blp bottles/frontend/ui/window.blp bottles/frontend/ui/fsr-dialog.blp @@ -70,7 +70,7 @@ bottles/frontend/widgets/importer_row.py bottles/frontend/widgets/installer_row.py bottles/frontend/widgets/library.py bottles/frontend/widgets/program_row.py -bottles/frontend/widgets/state.py +bottles/frontend/widgets/state_row.py bottles/frontend/windows/crash_report_dialog.py bottles/frontend/windows/display_dialog.py bottles/frontend/windows/dll_overrides_dialog.py From 4c17c190848f56729993cc31550527fc1309c3e7 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Sun, 12 Jan 2025 19:50:15 -0500 Subject: [PATCH 039/146] task-row: Rename file and class name --- bottles/frontend/operation.py | 14 +++++++------- bottles/frontend/ui/bottles.gresource.xml | 2 +- bottles/frontend/ui/meson.build | 2 +- .../frontend/ui/{task-entry.blp => task-row.blp} | 2 +- po/POTFILES | 2 +- 5 files changed, 11 insertions(+), 11 deletions(-) rename bottles/frontend/ui/{task-entry.blp => task-row.blp} (93%) diff --git a/bottles/frontend/operation.py b/bottles/frontend/operation.py index e681277f06d..8ed298cc9e3 100644 --- a/bottles/frontend/operation.py +++ b/bottles/frontend/operation.py @@ -23,9 +23,9 @@ from bottles.backend.state import TaskManager -@Gtk.Template(resource_path="/com/usebottles/bottles/task-entry.ui") -class TaskEntry(Adw.ActionRow): - __gtype_name__ = "TaskEntry" +@Gtk.Template(resource_path="/com/usebottles/bottles/task-row.ui") +class TaskRow(Adw.ActionRow): + __gtype_name__ = "TaskRow" # region Widgets btn_cancel = Gtk.Template.Child() @@ -52,14 +52,14 @@ def update(self, subtitle: str): class TaskSyncer: """Keep task list updated with backend TaskManager""" - _TASK_WIDGETS: Dict[UUID, TaskEntry] = {} + _TASK_WIDGETS: Dict[UUID, TaskRow] = {} def __init__(self, window): self.window = window - def _new_widget(self, title, cancellable=True) -> TaskEntry: - """create TaskEntry widget & add to task list""" - task_entry = TaskEntry(self.window, title, cancellable) + def _new_widget(self, title, cancellable=True) -> TaskRow: + """create TaskRow widget & add to task list""" + task_entry = TaskRow(self.window, title, cancellable) self.window.page_details.list_tasks.append(task_entry) return task_entry diff --git a/bottles/frontend/ui/bottles.gresource.xml b/bottles/frontend/ui/bottles.gresource.xml index 9a9e3edc847..280160c12ab 100644 --- a/bottles/frontend/ui/bottles.gresource.xml +++ b/bottles/frontend/ui/bottles.gresource.xml @@ -10,7 +10,7 @@ loading-view.ui bottle-row.ui check-row.ui - task-entry.ui + task-row.ui dependency-entry-row.ui program-row.ui importer-row.ui diff --git a/bottles/frontend/ui/meson.build b/bottles/frontend/ui/meson.build index 66057a72784..a35cd669f40 100644 --- a/bottles/frontend/ui/meson.build +++ b/bottles/frontend/ui/meson.build @@ -50,7 +50,7 @@ blueprints = custom_target('blueprints', 'preferences.blp', 'program-row.blp', 'state-row.blp', - 'task-entry.blp', + 'task-row.blp', 'window.blp', 'details-preferences-page.blp', 'help-overlay.blp', diff --git a/bottles/frontend/ui/task-entry.blp b/bottles/frontend/ui/task-row.blp similarity index 93% rename from bottles/frontend/ui/task-entry.blp rename to bottles/frontend/ui/task-row.blp index 1fe4d4fe524..c4da07a148e 100644 --- a/bottles/frontend/ui/task-entry.blp +++ b/bottles/frontend/ui/task-row.blp @@ -1,7 +1,7 @@ using Gtk 4.0; using Adw 1; -template $TaskEntry: Adw.ActionRow { +template $TaskRow: Adw.ActionRow { Box { spacing: 10; diff --git a/po/POTFILES b/po/POTFILES index f1e3400fdeb..d491a62b991 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -51,7 +51,7 @@ bottles/frontend/ui/onboard-dialog.blp bottles/frontend/ui/preferences.blp bottles/frontend/ui/program-row.blp bottles/frontend/ui/state-row.blp -bottles/frontend/ui/task-entry.blp +bottles/frontend/ui/task-row.blp bottles/frontend/ui/window.blp bottles/frontend/ui/fsr-dialog.blp bottles/frontend/views/bottle_details_page.py From f3aa6a7004bf00eac7ef75b29febde995c38d60a Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Mon, 13 Jan 2025 13:26:23 -0500 Subject: [PATCH 040/146] environment-variables-dialog: Rename files --- bottles/frontend/ui/bottles.gresource.xml | 2 +- ...dialog-env-vars.blp => environment-variables-dialog.blp} | 0 bottles/frontend/ui/meson.build | 2 +- bottles/frontend/views/details_preferences_page.py | 4 +++- .../windows/{envvars.py => environment_variables_dialog.py} | 6 +++--- bottles/frontend/windows/meson.build | 2 +- po/POTFILES | 4 ++-- 7 files changed, 11 insertions(+), 9 deletions(-) rename bottles/frontend/ui/{dialog-env-vars.blp => environment-variables-dialog.blp} (100%) rename bottles/frontend/windows/{envvars.py => environment_variables_dialog.py} (97%) diff --git a/bottles/frontend/ui/bottles.gresource.xml b/bottles/frontend/ui/bottles.gresource.xml index 280160c12ab..a8b6dea1e6d 100644 --- a/bottles/frontend/ui/bottles.gresource.xml +++ b/bottles/frontend/ui/bottles.gresource.xml @@ -35,7 +35,7 @@ library-view.ui dialog-launch-options.ui dll-overrides-dialog.ui - dialog-env-vars.ui + environment-variables-dialog.ui crash-report-dialog.ui duplicate-dialog.ui dialog-rename.ui diff --git a/bottles/frontend/ui/dialog-env-vars.blp b/bottles/frontend/ui/environment-variables-dialog.blp similarity index 100% rename from bottles/frontend/ui/dialog-env-vars.blp rename to bottles/frontend/ui/environment-variables-dialog.blp diff --git a/bottles/frontend/ui/meson.build b/bottles/frontend/ui/meson.build index a35cd669f40..b0d9dfdf40a 100644 --- a/bottles/frontend/ui/meson.build +++ b/bottles/frontend/ui/meson.build @@ -17,7 +17,7 @@ blueprints = custom_target('blueprints', 'dll-overrides-dialog.blp', 'drives-dialog.blp', 'duplicate-dialog.blp', - 'dialog-env-vars.blp', + 'environment-variables-dialog.blp', 'exclusion-patterns-dialog.blp', 'gamescope-dialog.blp', 'dialog-installer.blp', diff --git a/bottles/frontend/views/details_preferences_page.py b/bottles/frontend/views/details_preferences_page.py index 09b8cde1389..07082dc3f64 100644 --- a/bottles/frontend/views/details_preferences_page.py +++ b/bottles/frontend/views/details_preferences_page.py @@ -46,7 +46,9 @@ from bottles.frontend.windows.display_dialog import DisplayDialog from bottles.frontend.windows.dll_overrides_dialog import DLLOverridesDialog from bottles.frontend.windows.drives_dialog import DrivesDialog -from bottles.frontend.windows.envvars import EnvironmentVariablesDialog +from bottles.frontend.windows.environment_variables_dialog import ( + EnvironmentVariablesDialog, +) from bottles.frontend.windows.exclusion_patterns_dialog import ExclusionPatternsDialog from bottles.frontend.windows.fsr_dialog import FsrDialog from bottles.frontend.windows.gamescope_dialog import GamescopeDialog diff --git a/bottles/frontend/windows/envvars.py b/bottles/frontend/windows/environment_variables_dialog.py similarity index 97% rename from bottles/frontend/windows/envvars.py rename to bottles/frontend/windows/environment_variables_dialog.py index 85815f1433d..8ca9de36571 100644 --- a/bottles/frontend/windows/envvars.py +++ b/bottles/frontend/windows/environment_variables_dialog.py @@ -1,6 +1,6 @@ -# envvars.py +# environment_variables_dialog.py # -# Copyright 2022 brombinmirko +# Copyright 2025 The Bottles Contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -122,7 +122,7 @@ def __validate(self, *_args): self.add_css_class("error") -@Gtk.Template(resource_path="/com/usebottles/bottles/dialog-env-vars.ui") +@Gtk.Template(resource_path="/com/usebottles/bottles/environment-variables-dialog.ui") class EnvironmentVariablesDialog(Adw.Dialog): __gtype_name__ = "EnvironmentVariablesDialog" diff --git a/bottles/frontend/windows/meson.build b/bottles/frontend/windows/meson.build index 843854605d7..87c27c82bde 100644 --- a/bottles/frontend/windows/meson.build +++ b/bottles/frontend/windows/meson.build @@ -6,7 +6,7 @@ bottles_sources = [ 'crash_report_dialog.py', 'dll_overrides_dialog.py', 'duplicate_dialog.py', - 'envvars.py', + 'environment_variables_dialog.py', 'generic.py', 'launchoptions.py', 'onboard_dialog.py', diff --git a/po/POTFILES b/po/POTFILES index d491a62b991..404a3a2b748 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -21,7 +21,7 @@ bottles/frontend/ui/dependencies-check-dialog.blp bottles/frontend/ui/dll-overrides-dialog.blp bottles/frontend/ui/drives-dialog.blp bottles/frontend/ui/duplicate-dialog.blp -bottles/frontend/ui/dialog-env-vars.blp +bottles/frontend/ui/environment-variables-dialog.blp bottles/frontend/ui/exclusion-patterns-dialog.blp bottles/frontend/ui/gamescope-dialog.blp bottles/frontend/ui/dialog-installer.blp @@ -75,7 +75,7 @@ bottles/frontend/windows/crash_report_dialog.py bottles/frontend/windows/display_dialog.py bottles/frontend/windows/dll_overrides_dialog.py bottles/frontend/windows/drives_dialog.py -bottles/frontend/windows/envvars.py +bottles/frontend/windows/environment_variables_dialog.py bottles/frontend/windows/exclusion_patterns_dialog.py bottles/frontend/windows/generic.py bottles/frontend/windows/installer.py From c83e26279d474528d27c8e99410d91526392c2cf Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Mon, 13 Jan 2025 13:29:08 -0500 Subject: [PATCH 041/146] installer-dialog: Rename files --- bottles/frontend/ui/bottles.gresource.xml | 2 +- .../ui/{dialog-installer.blp => installer-dialog.blp} | 0 bottles/frontend/ui/meson.build | 2 +- bottles/frontend/widgets/installer_row.py | 2 +- .../frontend/windows/{installer.py => installer_dialog.py} | 6 +++--- bottles/frontend/windows/meson.build | 2 +- po/POTFILES | 4 ++-- 7 files changed, 9 insertions(+), 9 deletions(-) rename bottles/frontend/ui/{dialog-installer.blp => installer-dialog.blp} (100%) rename bottles/frontend/windows/{installer.py => installer_dialog.py} (98%) diff --git a/bottles/frontend/ui/bottles.gresource.xml b/bottles/frontend/ui/bottles.gresource.xml index a8b6dea1e6d..d1678257c58 100644 --- a/bottles/frontend/ui/bottles.gresource.xml +++ b/bottles/frontend/ui/bottles.gresource.xml @@ -47,7 +47,7 @@ drives-dialog.ui dialog-journal.ui dialog-sandbox.ui - dialog-installer.ui + installer-dialog.ui bottle-picker-dialog.ui dialog-proton-alert.ui dependencies-check-dialog.ui diff --git a/bottles/frontend/ui/dialog-installer.blp b/bottles/frontend/ui/installer-dialog.blp similarity index 100% rename from bottles/frontend/ui/dialog-installer.blp rename to bottles/frontend/ui/installer-dialog.blp diff --git a/bottles/frontend/ui/meson.build b/bottles/frontend/ui/meson.build index b0d9dfdf40a..01edd062a25 100644 --- a/bottles/frontend/ui/meson.build +++ b/bottles/frontend/ui/meson.build @@ -20,7 +20,7 @@ blueprints = custom_target('blueprints', 'environment-variables-dialog.blp', 'exclusion-patterns-dialog.blp', 'gamescope-dialog.blp', - 'dialog-installer.blp', + 'installer-dialog.blp', 'dialog-journal.blp', 'dialog-launch-options.blp', 'dialog-proton-alert.blp', diff --git a/bottles/frontend/widgets/installer_row.py b/bottles/frontend/widgets/installer_row.py index cf001399cba..6860dff9dc2 100644 --- a/bottles/frontend/widgets/installer_row.py +++ b/bottles/frontend/widgets/installer_row.py @@ -20,7 +20,7 @@ import webbrowser from bottles.frontend.windows.generic import SourceDialog -from bottles.frontend.windows.installer import InstallerDialog +from bottles.frontend.windows.installer_dialog import InstallerDialog @Gtk.Template(resource_path="/com/usebottles/bottles/installer-row.ui") diff --git a/bottles/frontend/windows/installer.py b/bottles/frontend/windows/installer_dialog.py similarity index 98% rename from bottles/frontend/windows/installer.py rename to bottles/frontend/windows/installer_dialog.py index dc520466e67..9479c214e8a 100644 --- a/bottles/frontend/windows/installer.py +++ b/bottles/frontend/windows/installer_dialog.py @@ -1,6 +1,6 @@ -# installer.py +# installer_dialog.py # -# Copyright 2022 brombinmirko +# Copyright 2025 The Bottles Contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -70,7 +70,7 @@ def set_path(_dialog, response): dialog.show() -@Gtk.Template(resource_path="/com/usebottles/bottles/dialog-installer.ui") +@Gtk.Template(resource_path="/com/usebottles/bottles/installer-dialog.ui") class InstallerDialog(Adw.Window): __gtype_name__ = "InstallerDialog" __sections = {} diff --git a/bottles/frontend/windows/meson.build b/bottles/frontend/windows/meson.build index 87c27c82bde..fddf5e2fa6e 100644 --- a/bottles/frontend/windows/meson.build +++ b/bottles/frontend/windows/meson.build @@ -22,7 +22,7 @@ bottles_sources = [ 'bottle_picker_dialog.py', 'protonalert.py', 'sandbox.py', - 'installer.py', + 'installer_dialog.py', 'dependencies_check_dialog.py', 'exclusion_patterns_dialog.py', 'upgradeversioning.py', diff --git a/po/POTFILES b/po/POTFILES index 404a3a2b748..57d68406755 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -24,7 +24,7 @@ bottles/frontend/ui/duplicate-dialog.blp bottles/frontend/ui/environment-variables-dialog.blp bottles/frontend/ui/exclusion-patterns-dialog.blp bottles/frontend/ui/gamescope-dialog.blp -bottles/frontend/ui/dialog-installer.blp +bottles/frontend/ui/installer-dialog.blp bottles/frontend/ui/dialog-journal.blp bottles/frontend/ui/dialog-launch-options.blp bottles/frontend/ui/dialog-proton-alert.blp @@ -78,7 +78,7 @@ bottles/frontend/windows/drives_dialog.py bottles/frontend/windows/environment_variables_dialog.py bottles/frontend/windows/exclusion_patterns_dialog.py bottles/frontend/windows/generic.py -bottles/frontend/windows/installer.py +bottles/frontend/windows/installer_dialog.py bottles/frontend/windows/launchoptions.py bottles/frontend/windows/main_window.py bottles/frontend/windows/vkbasalt.py From 34d26cd3e69fe4f7e7658c26eb9681b369b771b1 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Mon, 13 Jan 2025 13:31:54 -0500 Subject: [PATCH 042/146] journal-dialog: Rename files --- bottles/frontend/ui/bottles.gresource.xml | 2 +- .../frontend/ui/{dialog-journal.blp => journal-dialog.blp} | 0 bottles/frontend/ui/meson.build | 2 +- bottles/frontend/windows/{journal.py => journal_dialog.py} | 6 +++--- bottles/frontend/windows/meson.build | 2 +- po/POTFILES | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) rename bottles/frontend/ui/{dialog-journal.blp => journal-dialog.blp} (100%) rename bottles/frontend/windows/{journal.py => journal_dialog.py} (96%) diff --git a/bottles/frontend/ui/bottles.gresource.xml b/bottles/frontend/ui/bottles.gresource.xml index d1678257c58..db55e07e8fb 100644 --- a/bottles/frontend/ui/bottles.gresource.xml +++ b/bottles/frontend/ui/bottles.gresource.xml @@ -45,7 +45,7 @@ dialog-mangohud.ui display-dialog.ui drives-dialog.ui - dialog-journal.ui + journal-dialog.ui dialog-sandbox.ui installer-dialog.ui bottle-picker-dialog.ui diff --git a/bottles/frontend/ui/dialog-journal.blp b/bottles/frontend/ui/journal-dialog.blp similarity index 100% rename from bottles/frontend/ui/dialog-journal.blp rename to bottles/frontend/ui/journal-dialog.blp diff --git a/bottles/frontend/ui/meson.build b/bottles/frontend/ui/meson.build index 01edd062a25..d8a83f4aaac 100644 --- a/bottles/frontend/ui/meson.build +++ b/bottles/frontend/ui/meson.build @@ -21,7 +21,7 @@ blueprints = custom_target('blueprints', 'exclusion-patterns-dialog.blp', 'gamescope-dialog.blp', 'installer-dialog.blp', - 'dialog-journal.blp', + 'journal-dialog.blp', 'dialog-launch-options.blp', 'dialog-proton-alert.blp', 'dialog-rename.blp', diff --git a/bottles/frontend/windows/journal.py b/bottles/frontend/windows/journal_dialog.py similarity index 96% rename from bottles/frontend/windows/journal.py rename to bottles/frontend/windows/journal_dialog.py index 9199d1bae4a..5540bc307ee 100644 --- a/bottles/frontend/windows/journal.py +++ b/bottles/frontend/windows/journal_dialog.py @@ -1,6 +1,6 @@ -# journal.py +# journal_dialog.py # -# Copyright 2022 brombinmirko +# Copyright 2025 The Bottles Contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -20,7 +20,7 @@ from bottles.backend.managers.journal import JournalManager, JournalSeverity -@Gtk.Template(resource_path="/com/usebottles/bottles/dialog-journal.ui") +@Gtk.Template(resource_path="/com/usebottles/bottles/journal-dialog.ui") class JournalDialog(Adw.Window): __gtype_name__ = "JournalDialog" diff --git a/bottles/frontend/windows/meson.build b/bottles/frontend/windows/meson.build index fddf5e2fa6e..0270ba873d7 100644 --- a/bottles/frontend/windows/meson.build +++ b/bottles/frontend/windows/meson.build @@ -18,7 +18,7 @@ bottles_sources = [ 'mangohud.py', 'display_dialog.py', 'generic_cli.py', - 'journal.py', + 'journal_dialog.py', 'bottle_picker_dialog.py', 'protonalert.py', 'sandbox.py', diff --git a/po/POTFILES b/po/POTFILES index 57d68406755..d5c63fb1809 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -25,7 +25,7 @@ bottles/frontend/ui/environment-variables-dialog.blp bottles/frontend/ui/exclusion-patterns-dialog.blp bottles/frontend/ui/gamescope-dialog.blp bottles/frontend/ui/installer-dialog.blp -bottles/frontend/ui/dialog-journal.blp +bottles/frontend/ui/journal-dialog.blp bottles/frontend/ui/dialog-launch-options.blp bottles/frontend/ui/dialog-proton-alert.blp bottles/frontend/ui/dialog-rename.blp From 9c5f9d071fe6b2a6d3b5f8665f4eea177ab5bfb5 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Mon, 13 Jan 2025 13:34:36 -0500 Subject: [PATCH 043/146] launch-options-dialog: Rename files --- bottles/frontend/ui/bottles.gresource.xml | 2 +- ...{dialog-launch-options.blp => launch-options-dialog.blp} | 0 bottles/frontend/ui/meson.build | 2 +- bottles/frontend/widgets/program_row.py | 2 +- .../windows/{launchoptions.py => launch_options_dialog.py} | 6 +++--- bottles/frontend/windows/meson.build | 2 +- po/POTFILES | 4 ++-- 7 files changed, 9 insertions(+), 9 deletions(-) rename bottles/frontend/ui/{dialog-launch-options.blp => launch-options-dialog.blp} (100%) rename bottles/frontend/windows/{launchoptions.py => launch_options_dialog.py} (99%) diff --git a/bottles/frontend/ui/bottles.gresource.xml b/bottles/frontend/ui/bottles.gresource.xml index db55e07e8fb..5b9a0afe7f6 100644 --- a/bottles/frontend/ui/bottles.gresource.xml +++ b/bottles/frontend/ui/bottles.gresource.xml @@ -33,7 +33,7 @@ preferences.ui importer-view.ui library-view.ui - dialog-launch-options.ui + launch-options-dialog.ui dll-overrides-dialog.ui environment-variables-dialog.ui crash-report-dialog.ui diff --git a/bottles/frontend/ui/dialog-launch-options.blp b/bottles/frontend/ui/launch-options-dialog.blp similarity index 100% rename from bottles/frontend/ui/dialog-launch-options.blp rename to bottles/frontend/ui/launch-options-dialog.blp diff --git a/bottles/frontend/ui/meson.build b/bottles/frontend/ui/meson.build index d8a83f4aaac..7e851b12e65 100644 --- a/bottles/frontend/ui/meson.build +++ b/bottles/frontend/ui/meson.build @@ -22,7 +22,7 @@ blueprints = custom_target('blueprints', 'gamescope-dialog.blp', 'installer-dialog.blp', 'journal-dialog.blp', - 'dialog-launch-options.blp', + 'launch-options-dialog.blp', 'dialog-proton-alert.blp', 'dialog-rename.blp', 'dialog-sandbox.blp', diff --git a/bottles/frontend/widgets/program_row.py b/bottles/frontend/widgets/program_row.py index 3158d02f12f..1241fac11b0 100644 --- a/bottles/frontend/widgets/program_row.py +++ b/bottles/frontend/widgets/program_row.py @@ -29,7 +29,7 @@ from bottles.backend.wine.uninstaller import Uninstaller from bottles.backend.wine.winedbg import WineDbg from bottles.frontend.utils.gtk import GtkUtils -from bottles.frontend.windows.launchoptions import LaunchOptionsDialog +from bottles.frontend.windows.launch_options_dialog import LaunchOptionsDialog from bottles.frontend.windows.rename import RenameDialog diff --git a/bottles/frontend/windows/launchoptions.py b/bottles/frontend/windows/launch_options_dialog.py similarity index 99% rename from bottles/frontend/windows/launchoptions.py rename to bottles/frontend/windows/launch_options_dialog.py index 1b1550d0133..2fbbbc95944 100644 --- a/bottles/frontend/windows/launchoptions.py +++ b/bottles/frontend/windows/launch_options_dialog.py @@ -1,6 +1,6 @@ -# launchoptions.py +# launch_options_dialog.py # -# Copyright 2022 brombinmirko +# Copyright 2025 The Bottles Contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -24,7 +24,7 @@ logging = Logger() -@Gtk.Template(resource_path="/com/usebottles/bottles/dialog-launch-options.ui") +@Gtk.Template(resource_path="/com/usebottles/bottles/launch-options-dialog.ui") class LaunchOptionsDialog(Adw.Window): __gtype_name__ = "LaunchOptionsDialog" __gsignals__ = { diff --git a/bottles/frontend/windows/meson.build b/bottles/frontend/windows/meson.build index 0270ba873d7..86a07a85e57 100644 --- a/bottles/frontend/windows/meson.build +++ b/bottles/frontend/windows/meson.build @@ -8,7 +8,7 @@ bottles_sources = [ 'duplicate_dialog.py', 'environment_variables_dialog.py', 'generic.py', - 'launchoptions.py', + 'launch_options_dialog.py', 'onboard_dialog.py', 'rename.py', 'drives_dialog.py', diff --git a/po/POTFILES b/po/POTFILES index d5c63fb1809..160ac8767e2 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -26,7 +26,7 @@ bottles/frontend/ui/exclusion-patterns-dialog.blp bottles/frontend/ui/gamescope-dialog.blp bottles/frontend/ui/installer-dialog.blp bottles/frontend/ui/journal-dialog.blp -bottles/frontend/ui/dialog-launch-options.blp +bottles/frontend/ui/launch-options-dialog.blp bottles/frontend/ui/dialog-proton-alert.blp bottles/frontend/ui/dialog-rename.blp bottles/frontend/ui/dialog-run-args.blp @@ -79,7 +79,7 @@ bottles/frontend/windows/environment_variables_dialog.py bottles/frontend/windows/exclusion_patterns_dialog.py bottles/frontend/windows/generic.py bottles/frontend/windows/installer_dialog.py -bottles/frontend/windows/launchoptions.py +bottles/frontend/windows/launch_options_dialog.py bottles/frontend/windows/main_window.py bottles/frontend/windows/vkbasalt.py bottles/frontend/windows/fsr_dialog.py From bf1e7164fbd20b125cfddfafea394f233bd6819d Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Mon, 13 Jan 2025 13:40:53 -0500 Subject: [PATCH 044/146] mangohud-dialog: Rename files and add to POTFILES --- bottles/frontend/ui/bottles.gresource.xml | 2 +- .../ui/{dialog-mangohud.blp => mangohud-dialog.blp} | 0 bottles/frontend/ui/meson.build | 2 +- bottles/frontend/views/details_preferences_page.py | 2 +- .../frontend/windows/{mangohud.py => mangohud_dialog.py} | 6 +++--- bottles/frontend/windows/meson.build | 2 +- po/POTFILES | 2 ++ 7 files changed, 9 insertions(+), 7 deletions(-) rename bottles/frontend/ui/{dialog-mangohud.blp => mangohud-dialog.blp} (100%) rename bottles/frontend/windows/{mangohud.py => mangohud_dialog.py} (93%) diff --git a/bottles/frontend/ui/bottles.gresource.xml b/bottles/frontend/ui/bottles.gresource.xml index 5b9a0afe7f6..94ad4f021ca 100644 --- a/bottles/frontend/ui/bottles.gresource.xml +++ b/bottles/frontend/ui/bottles.gresource.xml @@ -42,7 +42,7 @@ gamescope-dialog.ui dialog-vkbasalt.ui fsr-dialog.ui - dialog-mangohud.ui + mangohud-dialog.ui display-dialog.ui drives-dialog.ui journal-dialog.ui diff --git a/bottles/frontend/ui/dialog-mangohud.blp b/bottles/frontend/ui/mangohud-dialog.blp similarity index 100% rename from bottles/frontend/ui/dialog-mangohud.blp rename to bottles/frontend/ui/mangohud-dialog.blp diff --git a/bottles/frontend/ui/meson.build b/bottles/frontend/ui/meson.build index 7e851b12e65..cea7093c0dd 100644 --- a/bottles/frontend/ui/meson.build +++ b/bottles/frontend/ui/meson.build @@ -31,7 +31,7 @@ blueprints = custom_target('blueprints', 'display-dialog.blp', 'dialog-vmtouch.blp', 'fsr-dialog.blp', - 'dialog-mangohud.blp', + 'mangohud-dialog.blp', 'dll-override-entry.blp', 'drive-entry.blp', 'env-var-entry.blp', diff --git a/bottles/frontend/views/details_preferences_page.py b/bottles/frontend/views/details_preferences_page.py index 07082dc3f64..e6adf416e9a 100644 --- a/bottles/frontend/views/details_preferences_page.py +++ b/bottles/frontend/views/details_preferences_page.py @@ -52,7 +52,7 @@ from bottles.frontend.windows.exclusion_patterns_dialog import ExclusionPatternsDialog from bottles.frontend.windows.fsr_dialog import FsrDialog from bottles.frontend.windows.gamescope_dialog import GamescopeDialog -from bottles.frontend.windows.mangohud import MangoHudDialog +from bottles.frontend.windows.mangohud_dialog import MangoHudDialog from bottles.frontend.windows.protonalert import ProtonAlertDialog from bottles.frontend.windows.sandbox import SandboxDialog from bottles.frontend.windows.vkbasalt import VkBasaltDialog diff --git a/bottles/frontend/windows/mangohud.py b/bottles/frontend/windows/mangohud_dialog.py similarity index 93% rename from bottles/frontend/windows/mangohud.py rename to bottles/frontend/windows/mangohud_dialog.py index 77e47df06e5..7690c2ac539 100644 --- a/bottles/frontend/windows/mangohud.py +++ b/bottles/frontend/windows/mangohud_dialog.py @@ -1,6 +1,6 @@ -# mangohud.py +# mangohud_dialog.py # -# Copyright 2022 Bottles Contributors +# Copyright 2025 The Bottles Contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -21,7 +21,7 @@ logging = Logger() -@Gtk.Template(resource_path="/com/usebottles/bottles/dialog-mangohud.ui") +@Gtk.Template(resource_path="/com/usebottles/bottles/mangohud-dialog.ui") class MangoHudDialog(Adw.Window): __gtype_name__ = "MangoHudDialog" diff --git a/bottles/frontend/windows/meson.build b/bottles/frontend/windows/meson.build index 86a07a85e57..4e3db1630b8 100644 --- a/bottles/frontend/windows/meson.build +++ b/bottles/frontend/windows/meson.build @@ -15,7 +15,7 @@ bottles_sources = [ 'gamescope_dialog.py', 'vkbasalt.py', 'fsr_dialog.py', - 'mangohud.py', + 'mangohud_dialog.py', 'display_dialog.py', 'generic_cli.py', 'journal_dialog.py', diff --git a/po/POTFILES b/po/POTFILES index 160ac8767e2..9e33331f506 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -33,6 +33,7 @@ bottles/frontend/ui/dialog-run-args.blp bottles/frontend/ui/dialog-sandbox.blp bottles/frontend/ui/dialog-upgrade-versioning.blp bottles/frontend/ui/dialog-vkbasalt.blp +bottles/frontend/ui/mangohud-dialog.blp bottles/frontend/ui/dll-override-entry.blp bottles/frontend/ui/drive-entry.blp bottles/frontend/ui/env-var-entry.blp @@ -83,6 +84,7 @@ bottles/frontend/windows/launch_options_dialog.py bottles/frontend/windows/main_window.py bottles/frontend/windows/vkbasalt.py bottles/frontend/windows/fsr_dialog.py +bottles/frontend/windows/mangohud_dialog.py data/com.usebottles.bottles.desktop.in.in data/com.usebottles.bottles.gschema.xml data/com.usebottles.bottles.metainfo.xml.in From b89bbc5bcc694e0c0deccd9b9dd133da3c39cb33 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Mon, 13 Jan 2025 13:42:52 -0500 Subject: [PATCH 045/146] proton-alert-dialog: Rename files --- bottles/frontend/ui/bottles.gresource.xml | 2 +- bottles/frontend/ui/meson.build | 2 +- .../ui/{dialog-proton-alert.blp => proton-alert-dialog.blp} | 0 bottles/frontend/views/details_preferences_page.py | 2 +- bottles/frontend/windows/meson.build | 2 +- .../windows/{protonalert.py => proton_alert_dialog.py} | 6 +++--- po/POTFILES | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) rename bottles/frontend/ui/{dialog-proton-alert.blp => proton-alert-dialog.blp} (100%) rename bottles/frontend/windows/{protonalert.py => proton_alert_dialog.py} (91%) diff --git a/bottles/frontend/ui/bottles.gresource.xml b/bottles/frontend/ui/bottles.gresource.xml index 94ad4f021ca..d1551d59cc7 100644 --- a/bottles/frontend/ui/bottles.gresource.xml +++ b/bottles/frontend/ui/bottles.gresource.xml @@ -49,7 +49,7 @@ dialog-sandbox.ui installer-dialog.ui bottle-picker-dialog.ui - dialog-proton-alert.ui + proton-alert-dialog.ui dependencies-check-dialog.ui exclusion-patterns-dialog.ui dialog-upgrade-versioning.ui diff --git a/bottles/frontend/ui/meson.build b/bottles/frontend/ui/meson.build index cea7093c0dd..092355596e1 100644 --- a/bottles/frontend/ui/meson.build +++ b/bottles/frontend/ui/meson.build @@ -23,7 +23,7 @@ blueprints = custom_target('blueprints', 'installer-dialog.blp', 'journal-dialog.blp', 'launch-options-dialog.blp', - 'dialog-proton-alert.blp', + 'proton-alert-dialog.blp', 'dialog-rename.blp', 'dialog-sandbox.blp', 'dialog-upgrade-versioning.blp', diff --git a/bottles/frontend/ui/dialog-proton-alert.blp b/bottles/frontend/ui/proton-alert-dialog.blp similarity index 100% rename from bottles/frontend/ui/dialog-proton-alert.blp rename to bottles/frontend/ui/proton-alert-dialog.blp diff --git a/bottles/frontend/views/details_preferences_page.py b/bottles/frontend/views/details_preferences_page.py index e6adf416e9a..c9214427918 100644 --- a/bottles/frontend/views/details_preferences_page.py +++ b/bottles/frontend/views/details_preferences_page.py @@ -53,7 +53,7 @@ from bottles.frontend.windows.fsr_dialog import FsrDialog from bottles.frontend.windows.gamescope_dialog import GamescopeDialog from bottles.frontend.windows.mangohud_dialog import MangoHudDialog -from bottles.frontend.windows.protonalert import ProtonAlertDialog +from bottles.frontend.windows.proton_alert_dialog import ProtonAlertDialog from bottles.frontend.windows.sandbox import SandboxDialog from bottles.frontend.windows.vkbasalt import VkBasaltDialog from bottles.frontend.windows.vmtouch import VmtouchDialog diff --git a/bottles/frontend/windows/meson.build b/bottles/frontend/windows/meson.build index 4e3db1630b8..a52ab86291c 100644 --- a/bottles/frontend/windows/meson.build +++ b/bottles/frontend/windows/meson.build @@ -20,7 +20,7 @@ bottles_sources = [ 'generic_cli.py', 'journal_dialog.py', 'bottle_picker_dialog.py', - 'protonalert.py', + 'proton_alert_dialog.py', 'sandbox.py', 'installer_dialog.py', 'dependencies_check_dialog.py', diff --git a/bottles/frontend/windows/protonalert.py b/bottles/frontend/windows/proton_alert_dialog.py similarity index 91% rename from bottles/frontend/windows/protonalert.py rename to bottles/frontend/windows/proton_alert_dialog.py index c13a09a9e20..f4a860c2bdd 100644 --- a/bottles/frontend/windows/protonalert.py +++ b/bottles/frontend/windows/proton_alert_dialog.py @@ -1,6 +1,6 @@ -# protonalert.py +# proton_alert_dialog.py # -# Copyright 2022 brombinmirko +# Copyright 2025 The Bottles Contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -18,7 +18,7 @@ from gi.repository import Gtk, Adw -@Gtk.Template(resource_path="/com/usebottles/bottles/dialog-proton-alert.ui") +@Gtk.Template(resource_path="/com/usebottles/bottles/proton-alert-dialog.ui") class ProtonAlertDialog(Adw.Window): __gtype_name__ = "ProtonAlertDialog" __resources = {} diff --git a/po/POTFILES b/po/POTFILES index 9e33331f506..3bf61be6c11 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -27,7 +27,7 @@ bottles/frontend/ui/gamescope-dialog.blp bottles/frontend/ui/installer-dialog.blp bottles/frontend/ui/journal-dialog.blp bottles/frontend/ui/launch-options-dialog.blp -bottles/frontend/ui/dialog-proton-alert.blp +bottles/frontend/ui/proton-alert-dialog.blp bottles/frontend/ui/dialog-rename.blp bottles/frontend/ui/dialog-run-args.blp bottles/frontend/ui/dialog-sandbox.blp From 93ae9bb28c37683f4b2eec9f10e5c6dd4983e2e9 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Mon, 13 Jan 2025 13:44:39 -0500 Subject: [PATCH 046/146] rename-program-dialog: Rename files and class name --- bottles/frontend/ui/bottles.gresource.xml | 2 +- bottles/frontend/ui/meson.build | 2 +- .../{dialog-rename.blp => rename-program-dialog.blp} | 2 +- bottles/frontend/widgets/program_row.py | 6 ++++-- bottles/frontend/windows/meson.build | 2 +- .../windows/{rename.py => rename_program_dialog.py} | 10 +++++----- po/POTFILES | 2 +- 7 files changed, 14 insertions(+), 12 deletions(-) rename bottles/frontend/ui/{dialog-rename.blp => rename-program-dialog.blp} (93%) rename bottles/frontend/windows/{rename.py => rename_program_dialog.py} (88%) diff --git a/bottles/frontend/ui/bottles.gresource.xml b/bottles/frontend/ui/bottles.gresource.xml index d1551d59cc7..98a318e5b97 100644 --- a/bottles/frontend/ui/bottles.gresource.xml +++ b/bottles/frontend/ui/bottles.gresource.xml @@ -38,7 +38,7 @@ environment-variables-dialog.ui crash-report-dialog.ui duplicate-dialog.ui - dialog-rename.ui + rename-program-dialog.ui gamescope-dialog.ui dialog-vkbasalt.ui fsr-dialog.ui diff --git a/bottles/frontend/ui/meson.build b/bottles/frontend/ui/meson.build index 092355596e1..4d151f26577 100644 --- a/bottles/frontend/ui/meson.build +++ b/bottles/frontend/ui/meson.build @@ -24,7 +24,7 @@ blueprints = custom_target('blueprints', 'journal-dialog.blp', 'launch-options-dialog.blp', 'proton-alert-dialog.blp', - 'dialog-rename.blp', + 'rename-program-dialog.blp', 'dialog-sandbox.blp', 'dialog-upgrade-versioning.blp', 'dialog-vkbasalt.blp', diff --git a/bottles/frontend/ui/dialog-rename.blp b/bottles/frontend/ui/rename-program-dialog.blp similarity index 93% rename from bottles/frontend/ui/dialog-rename.blp rename to bottles/frontend/ui/rename-program-dialog.blp index 4c0b5cd79a5..bcf1c1e97b3 100644 --- a/bottles/frontend/ui/dialog-rename.blp +++ b/bottles/frontend/ui/rename-program-dialog.blp @@ -1,7 +1,7 @@ using Gtk 4.0; using Adw 1; -template $RenameDialog: Adw.Window { +template $RenameProgramDialog: Adw.Window { modal: true; deletable: false; default-width: 550; diff --git a/bottles/frontend/widgets/program_row.py b/bottles/frontend/widgets/program_row.py index 1241fac11b0..da602c4ac0f 100644 --- a/bottles/frontend/widgets/program_row.py +++ b/bottles/frontend/widgets/program_row.py @@ -30,7 +30,7 @@ from bottles.backend.wine.winedbg import WineDbg from bottles.frontend.utils.gtk import GtkUtils from bottles.frontend.windows.launch_options_dialog import LaunchOptionsDialog -from bottles.frontend.windows.rename import RenameDialog +from bottles.frontend.windows.rename_program_dialog import RenameProgramDialog # noinspection PyUnusedLocal @@ -275,7 +275,9 @@ def ui_update(_result, _error): RunAsync(async_work, callback=ui_update) - dialog = RenameDialog(self.window, on_save=func, name=self.program["name"]) + dialog = RenameProgramDialog( + self.window, on_save=func, name=self.program["name"] + ) dialog.present() def browse_program_folder(self, _widget): diff --git a/bottles/frontend/windows/meson.build b/bottles/frontend/windows/meson.build index a52ab86291c..ca2d71e9d04 100644 --- a/bottles/frontend/windows/meson.build +++ b/bottles/frontend/windows/meson.build @@ -10,7 +10,7 @@ bottles_sources = [ 'generic.py', 'launch_options_dialog.py', 'onboard_dialog.py', - 'rename.py', + 'rename_program_dialog.py', 'drives_dialog.py', 'gamescope_dialog.py', 'vkbasalt.py', diff --git a/bottles/frontend/windows/rename.py b/bottles/frontend/windows/rename_program_dialog.py similarity index 88% rename from bottles/frontend/windows/rename.py rename to bottles/frontend/windows/rename_program_dialog.py index e58535268e4..088edf18a6c 100644 --- a/bottles/frontend/windows/rename.py +++ b/bottles/frontend/windows/rename_program_dialog.py @@ -1,6 +1,6 @@ -# rename.py +# rename_program_dialog.py # -# Copyright 2022 brombinmirko +# Copyright 2025 The Bottles Contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -18,9 +18,9 @@ from gi.repository import Gtk, Adw -@Gtk.Template(resource_path="/com/usebottles/bottles/dialog-rename.ui") -class RenameDialog(Adw.Window): - __gtype_name__ = "RenameDialog" +@Gtk.Template(resource_path="/com/usebottles/bottles/rename-program-dialog.ui") +class RenameProgramDialog(Adw.Window): + __gtype_name__ = "RenameProgramDialog" # region Widgets entry_name = Gtk.Template.Child() diff --git a/po/POTFILES b/po/POTFILES index 3bf61be6c11..04bb470ef92 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -28,7 +28,7 @@ bottles/frontend/ui/installer-dialog.blp bottles/frontend/ui/journal-dialog.blp bottles/frontend/ui/launch-options-dialog.blp bottles/frontend/ui/proton-alert-dialog.blp -bottles/frontend/ui/dialog-rename.blp +bottles/frontend/ui/rename-program-dialog.blp bottles/frontend/ui/dialog-run-args.blp bottles/frontend/ui/dialog-sandbox.blp bottles/frontend/ui/dialog-upgrade-versioning.blp From 4711b81f610cb2067528f76c146fdc3f3eb2f113 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Mon, 13 Jan 2025 13:45:33 -0500 Subject: [PATCH 047/146] dialog-run-args: Remove file It's not being used --- bottles/frontend/ui/dialog-run-args.blp | 50 ------------------------- po/POTFILES | 1 - 2 files changed, 51 deletions(-) delete mode 100644 bottles/frontend/ui/dialog-run-args.blp diff --git a/bottles/frontend/ui/dialog-run-args.blp b/bottles/frontend/ui/dialog-run-args.blp deleted file mode 100644 index c718581a827..00000000000 --- a/bottles/frontend/ui/dialog-run-args.blp +++ /dev/null @@ -1,50 +0,0 @@ -using Gtk 4.0; -using Adw 1; - -template $RunArgsDialog: Window { - modal: true; - default-width: 550; - destroy-with-parent: true; - - [titlebar] - HeaderBar { - show-title-buttons: false; - - title-widget: Adw.WindowTitle { - title: _("Run With Arguments"); - }; - - [start] - Button btn_cancel { - label: _("Cancel"); - - ShortcutController { - scope: managed; - - Shortcut { - trigger: "Escape"; - action: "activate"; - } - } - } - - [end] - Button btn_run { - label: _("Run"); - - styles [ - "suggested-action", - ] - } - } - - Adw.PreferencesPage { - Adw.PreferencesGroup { - description: _("Write below the arguments to be passed to the executable."); - - Adw.EntryRow entry_args { - title: _("e.g.: -opengl -SkipBuildPatchPrereq"); - } - } - } -} diff --git a/po/POTFILES b/po/POTFILES index 04bb470ef92..57f851c30e0 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -29,7 +29,6 @@ bottles/frontend/ui/journal-dialog.blp bottles/frontend/ui/launch-options-dialog.blp bottles/frontend/ui/proton-alert-dialog.blp bottles/frontend/ui/rename-program-dialog.blp -bottles/frontend/ui/dialog-run-args.blp bottles/frontend/ui/dialog-sandbox.blp bottles/frontend/ui/dialog-upgrade-versioning.blp bottles/frontend/ui/dialog-vkbasalt.blp From ba725048f2c147a9577942b34c0acabfea009b02 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Mon, 13 Jan 2025 13:47:10 -0500 Subject: [PATCH 048/146] sandbox-dialog: Rename files --- bottles/frontend/ui/bottles.gresource.xml | 2 +- bottles/frontend/ui/meson.build | 2 +- .../frontend/ui/{dialog-sandbox.blp => sandbox-dialog.blp} | 0 bottles/frontend/views/details_preferences_page.py | 2 +- bottles/frontend/windows/meson.build | 2 +- bottles/frontend/windows/{sandbox.py => sandbox_dialog.py} | 6 +++--- po/POTFILES | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) rename bottles/frontend/ui/{dialog-sandbox.blp => sandbox-dialog.blp} (100%) rename bottles/frontend/windows/{sandbox.py => sandbox_dialog.py} (92%) diff --git a/bottles/frontend/ui/bottles.gresource.xml b/bottles/frontend/ui/bottles.gresource.xml index 98a318e5b97..81de23b3a12 100644 --- a/bottles/frontend/ui/bottles.gresource.xml +++ b/bottles/frontend/ui/bottles.gresource.xml @@ -46,7 +46,7 @@ display-dialog.ui drives-dialog.ui journal-dialog.ui - dialog-sandbox.ui + sandbox-dialog.ui installer-dialog.ui bottle-picker-dialog.ui proton-alert-dialog.ui diff --git a/bottles/frontend/ui/meson.build b/bottles/frontend/ui/meson.build index 4d151f26577..330fe1b3e30 100644 --- a/bottles/frontend/ui/meson.build +++ b/bottles/frontend/ui/meson.build @@ -25,7 +25,7 @@ blueprints = custom_target('blueprints', 'launch-options-dialog.blp', 'proton-alert-dialog.blp', 'rename-program-dialog.blp', - 'dialog-sandbox.blp', + 'sandbox-dialog.blp', 'dialog-upgrade-versioning.blp', 'dialog-vkbasalt.blp', 'display-dialog.blp', diff --git a/bottles/frontend/ui/dialog-sandbox.blp b/bottles/frontend/ui/sandbox-dialog.blp similarity index 100% rename from bottles/frontend/ui/dialog-sandbox.blp rename to bottles/frontend/ui/sandbox-dialog.blp diff --git a/bottles/frontend/views/details_preferences_page.py b/bottles/frontend/views/details_preferences_page.py index c9214427918..497a740a862 100644 --- a/bottles/frontend/views/details_preferences_page.py +++ b/bottles/frontend/views/details_preferences_page.py @@ -54,7 +54,7 @@ from bottles.frontend.windows.gamescope_dialog import GamescopeDialog from bottles.frontend.windows.mangohud_dialog import MangoHudDialog from bottles.frontend.windows.proton_alert_dialog import ProtonAlertDialog -from bottles.frontend.windows.sandbox import SandboxDialog +from bottles.frontend.windows.sandbox_dialog import SandboxDialog from bottles.frontend.windows.vkbasalt import VkBasaltDialog from bottles.frontend.windows.vmtouch import VmtouchDialog diff --git a/bottles/frontend/windows/meson.build b/bottles/frontend/windows/meson.build index ca2d71e9d04..21e9c6900c8 100644 --- a/bottles/frontend/windows/meson.build +++ b/bottles/frontend/windows/meson.build @@ -21,7 +21,7 @@ bottles_sources = [ 'journal_dialog.py', 'bottle_picker_dialog.py', 'proton_alert_dialog.py', - 'sandbox.py', + 'sandbox_dialog.py', 'installer_dialog.py', 'dependencies_check_dialog.py', 'exclusion_patterns_dialog.py', diff --git a/bottles/frontend/windows/sandbox.py b/bottles/frontend/windows/sandbox_dialog.py similarity index 92% rename from bottles/frontend/windows/sandbox.py rename to bottles/frontend/windows/sandbox_dialog.py index 84c7d98f06e..9f0bd1a1a07 100644 --- a/bottles/frontend/windows/sandbox.py +++ b/bottles/frontend/windows/sandbox_dialog.py @@ -1,6 +1,6 @@ -# sandbox.py +# sandbox_dialog.py # -# Copyright 2022 brombinmirko +# Copyright 2025 The Bottles Contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -18,7 +18,7 @@ from gi.repository import Gtk, Adw -@Gtk.Template(resource_path="/com/usebottles/bottles/dialog-sandbox.ui") +@Gtk.Template(resource_path="/com/usebottles/bottles/sandbox-dialog.ui") class SandboxDialog(Adw.Window): __gtype_name__ = "SandboxDialog" diff --git a/po/POTFILES b/po/POTFILES index 57f851c30e0..a1cf7509541 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -29,7 +29,7 @@ bottles/frontend/ui/journal-dialog.blp bottles/frontend/ui/launch-options-dialog.blp bottles/frontend/ui/proton-alert-dialog.blp bottles/frontend/ui/rename-program-dialog.blp -bottles/frontend/ui/dialog-sandbox.blp +bottles/frontend/ui/sandbox-dialog.blp bottles/frontend/ui/dialog-upgrade-versioning.blp bottles/frontend/ui/dialog-vkbasalt.blp bottles/frontend/ui/mangohud-dialog.blp From f6e6db789e4b1f9b2ea75688b4e2e937365507bf Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Mon, 13 Jan 2025 13:48:48 -0500 Subject: [PATCH 049/146] upgrade-versioning-dialog: Rename files --- bottles/frontend/ui/bottles.gresource.xml | 2 +- bottles/frontend/ui/meson.build | 2 +- ...upgrade-versioning.blp => upgrade-versioning-dialog.blp} | 0 bottles/frontend/views/bottle_details_page.py | 2 +- bottles/frontend/windows/meson.build | 2 +- .../{upgradeversioning.py => upgrade_versioning_dialog.py} | 6 +++--- po/POTFILES | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) rename bottles/frontend/ui/{dialog-upgrade-versioning.blp => upgrade-versioning-dialog.blp} (100%) rename bottles/frontend/windows/{upgradeversioning.py => upgrade_versioning_dialog.py} (94%) diff --git a/bottles/frontend/ui/bottles.gresource.xml b/bottles/frontend/ui/bottles.gresource.xml index 81de23b3a12..17557cfa16a 100644 --- a/bottles/frontend/ui/bottles.gresource.xml +++ b/bottles/frontend/ui/bottles.gresource.xml @@ -52,7 +52,7 @@ proton-alert-dialog.ui dependencies-check-dialog.ui exclusion-patterns-dialog.ui - dialog-upgrade-versioning.ui + upgrade-versioning-dialog.ui dialog-vmtouch.ui onboard-dialog.ui diff --git a/bottles/frontend/ui/meson.build b/bottles/frontend/ui/meson.build index 330fe1b3e30..3b2e0296881 100644 --- a/bottles/frontend/ui/meson.build +++ b/bottles/frontend/ui/meson.build @@ -26,7 +26,7 @@ blueprints = custom_target('blueprints', 'proton-alert-dialog.blp', 'rename-program-dialog.blp', 'sandbox-dialog.blp', - 'dialog-upgrade-versioning.blp', + 'upgrade-versioning-dialog.blp', 'dialog-vkbasalt.blp', 'display-dialog.blp', 'dialog-vmtouch.blp', diff --git a/bottles/frontend/ui/dialog-upgrade-versioning.blp b/bottles/frontend/ui/upgrade-versioning-dialog.blp similarity index 100% rename from bottles/frontend/ui/dialog-upgrade-versioning.blp rename to bottles/frontend/ui/upgrade-versioning-dialog.blp diff --git a/bottles/frontend/views/bottle_details_page.py b/bottles/frontend/views/bottle_details_page.py index 39b39065bfe..4c60ed69e45 100644 --- a/bottles/frontend/views/bottle_details_page.py +++ b/bottles/frontend/views/bottle_details_page.py @@ -43,7 +43,7 @@ from bottles.frontend.utils.gtk import GtkUtils from bottles.frontend.widgets.program_row import ProgramRow from bottles.frontend.windows.duplicate_dialog import DuplicateDialog -from bottles.frontend.windows.upgradeversioning import UpgradeVersioningDialog +from bottles.frontend.windows.upgrade_versioning_dialog import UpgradeVersioningDialog @Gtk.Template(resource_path="/com/usebottles/bottles/bottle-details-page.ui") diff --git a/bottles/frontend/windows/meson.build b/bottles/frontend/windows/meson.build index 21e9c6900c8..17bccefe17d 100644 --- a/bottles/frontend/windows/meson.build +++ b/bottles/frontend/windows/meson.build @@ -25,7 +25,7 @@ bottles_sources = [ 'installer_dialog.py', 'dependencies_check_dialog.py', 'exclusion_patterns_dialog.py', - 'upgradeversioning.py', + 'upgrade_versioning_dialog.py', 'vmtouch.py', 'window.py', ] diff --git a/bottles/frontend/windows/upgradeversioning.py b/bottles/frontend/windows/upgrade_versioning_dialog.py similarity index 94% rename from bottles/frontend/windows/upgradeversioning.py rename to bottles/frontend/windows/upgrade_versioning_dialog.py index f9ebe665a0e..cb5b2d8d34c 100644 --- a/bottles/frontend/windows/upgradeversioning.py +++ b/bottles/frontend/windows/upgrade_versioning_dialog.py @@ -1,6 +1,6 @@ -# duplicate.py +# upgrade_versioning_dialog.py # -# Copyright 2022 brombinmirko +# Copyright 2025 The Bottles Contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -21,7 +21,7 @@ from bottles.backend.utils.threading import RunAsync -@Gtk.Template(resource_path="/com/usebottles/bottles/dialog-upgrade-versioning.ui") +@Gtk.Template(resource_path="/com/usebottles/bottles/upgrade-versioning-dialog.ui") class UpgradeVersioningDialog(Adw.Window): __gtype_name__ = "UpgradeVersioningDialog" diff --git a/po/POTFILES b/po/POTFILES index a1cf7509541..e38bd6c6142 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -30,7 +30,7 @@ bottles/frontend/ui/launch-options-dialog.blp bottles/frontend/ui/proton-alert-dialog.blp bottles/frontend/ui/rename-program-dialog.blp bottles/frontend/ui/sandbox-dialog.blp -bottles/frontend/ui/dialog-upgrade-versioning.blp +bottles/frontend/ui/upgrade-versioning-dialog.blp bottles/frontend/ui/dialog-vkbasalt.blp bottles/frontend/ui/mangohud-dialog.blp bottles/frontend/ui/dll-override-entry.blp From 422bab824d23533548e6032142367ddf5851993f Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Mon, 13 Jan 2025 13:50:49 -0500 Subject: [PATCH 050/146] vkbasalt-dialog: Rename files --- bottles/frontend/ui/bottles.gresource.xml | 2 +- bottles/frontend/ui/meson.build | 2 +- .../ui/{dialog-vkbasalt.blp => vkbasalt-dialog.blp} | 0 bottles/frontend/views/details_preferences_page.py | 2 +- bottles/frontend/windows/meson.build | 2 +- .../frontend/windows/{vkbasalt.py => vkbasalt_dialog.py} | 6 +++--- po/POTFILES | 4 ++-- 7 files changed, 9 insertions(+), 9 deletions(-) rename bottles/frontend/ui/{dialog-vkbasalt.blp => vkbasalt-dialog.blp} (100%) rename bottles/frontend/windows/{vkbasalt.py => vkbasalt_dialog.py} (98%) diff --git a/bottles/frontend/ui/bottles.gresource.xml b/bottles/frontend/ui/bottles.gresource.xml index 17557cfa16a..b1979866827 100644 --- a/bottles/frontend/ui/bottles.gresource.xml +++ b/bottles/frontend/ui/bottles.gresource.xml @@ -40,7 +40,7 @@ duplicate-dialog.ui rename-program-dialog.ui gamescope-dialog.ui - dialog-vkbasalt.ui + vkbasalt-dialog.ui fsr-dialog.ui mangohud-dialog.ui display-dialog.ui diff --git a/bottles/frontend/ui/meson.build b/bottles/frontend/ui/meson.build index 3b2e0296881..58d31f3761c 100644 --- a/bottles/frontend/ui/meson.build +++ b/bottles/frontend/ui/meson.build @@ -27,7 +27,7 @@ blueprints = custom_target('blueprints', 'rename-program-dialog.blp', 'sandbox-dialog.blp', 'upgrade-versioning-dialog.blp', - 'dialog-vkbasalt.blp', + 'vkbasalt-dialog.blp', 'display-dialog.blp', 'dialog-vmtouch.blp', 'fsr-dialog.blp', diff --git a/bottles/frontend/ui/dialog-vkbasalt.blp b/bottles/frontend/ui/vkbasalt-dialog.blp similarity index 100% rename from bottles/frontend/ui/dialog-vkbasalt.blp rename to bottles/frontend/ui/vkbasalt-dialog.blp diff --git a/bottles/frontend/views/details_preferences_page.py b/bottles/frontend/views/details_preferences_page.py index 497a740a862..57e82d2e139 100644 --- a/bottles/frontend/views/details_preferences_page.py +++ b/bottles/frontend/views/details_preferences_page.py @@ -55,7 +55,7 @@ from bottles.frontend.windows.mangohud_dialog import MangoHudDialog from bottles.frontend.windows.proton_alert_dialog import ProtonAlertDialog from bottles.frontend.windows.sandbox_dialog import SandboxDialog -from bottles.frontend.windows.vkbasalt import VkBasaltDialog +from bottles.frontend.windows.vkbasalt_dialog import VkBasaltDialog from bottles.frontend.windows.vmtouch import VmtouchDialog logging = Logger() diff --git a/bottles/frontend/windows/meson.build b/bottles/frontend/windows/meson.build index 17bccefe17d..fb35209eb6f 100644 --- a/bottles/frontend/windows/meson.build +++ b/bottles/frontend/windows/meson.build @@ -13,7 +13,7 @@ bottles_sources = [ 'rename_program_dialog.py', 'drives_dialog.py', 'gamescope_dialog.py', - 'vkbasalt.py', + 'vkbasalt_dialog.py', 'fsr_dialog.py', 'mangohud_dialog.py', 'display_dialog.py', diff --git a/bottles/frontend/windows/vkbasalt.py b/bottles/frontend/windows/vkbasalt_dialog.py similarity index 98% rename from bottles/frontend/windows/vkbasalt.py rename to bottles/frontend/windows/vkbasalt_dialog.py index 8a3950f8c90..f3f77c66454 100644 --- a/bottles/frontend/windows/vkbasalt.py +++ b/bottles/frontend/windows/vkbasalt_dialog.py @@ -1,6 +1,6 @@ -# vkbasalt.py +# vkbasalt_dialog.py # -# Copyright 2022 Hari Rana / TheEvilSkeleton +# Copyright 2025 The Bottles Contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -55,7 +55,7 @@ class VkBasaltSettings: exec = False -@Gtk.Template(resource_path="/com/usebottles/bottles/dialog-vkbasalt.ui") +@Gtk.Template(resource_path="/com/usebottles/bottles/vkbasalt-dialog.ui") class VkBasaltDialog(Adw.Window): __gtype_name__ = "VkBasaltDialog" diff --git a/po/POTFILES b/po/POTFILES index e38bd6c6142..5c8aea01faf 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -31,7 +31,7 @@ bottles/frontend/ui/proton-alert-dialog.blp bottles/frontend/ui/rename-program-dialog.blp bottles/frontend/ui/sandbox-dialog.blp bottles/frontend/ui/upgrade-versioning-dialog.blp -bottles/frontend/ui/dialog-vkbasalt.blp +bottles/frontend/ui/vkbasalt-dialog.blp bottles/frontend/ui/mangohud-dialog.blp bottles/frontend/ui/dll-override-entry.blp bottles/frontend/ui/drive-entry.blp @@ -81,7 +81,7 @@ bottles/frontend/windows/generic.py bottles/frontend/windows/installer_dialog.py bottles/frontend/windows/launch_options_dialog.py bottles/frontend/windows/main_window.py -bottles/frontend/windows/vkbasalt.py +bottles/frontend/windows/vkbasalt_dialog.py bottles/frontend/windows/fsr_dialog.py bottles/frontend/windows/mangohud_dialog.py data/com.usebottles.bottles.desktop.in.in From 7a167886be8db87ff4c1c069d5e018099de857f6 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Mon, 13 Jan 2025 13:53:15 -0500 Subject: [PATCH 051/146] vmtouch-dialog: Rename files and add to POTFILES --- bottles/frontend/ui/bottles.gresource.xml | 2 +- bottles/frontend/ui/meson.build | 2 +- .../frontend/ui/{dialog-vmtouch.blp => vmtouch-dialog.blp} | 0 bottles/frontend/views/details_preferences_page.py | 2 +- bottles/frontend/windows/meson.build | 2 +- bottles/frontend/windows/{vmtouch.py => vmtouch_dialog.py} | 6 +++--- po/POTFILES | 1 + 7 files changed, 8 insertions(+), 7 deletions(-) rename bottles/frontend/ui/{dialog-vmtouch.blp => vmtouch-dialog.blp} (100%) rename bottles/frontend/windows/{vmtouch.py => vmtouch_dialog.py} (93%) diff --git a/bottles/frontend/ui/bottles.gresource.xml b/bottles/frontend/ui/bottles.gresource.xml index b1979866827..de4e8a76360 100644 --- a/bottles/frontend/ui/bottles.gresource.xml +++ b/bottles/frontend/ui/bottles.gresource.xml @@ -53,7 +53,7 @@ dependencies-check-dialog.ui exclusion-patterns-dialog.ui upgrade-versioning-dialog.ui - dialog-vmtouch.ui + vmtouch-dialog.ui onboard-dialog.ui diff --git a/bottles/frontend/ui/meson.build b/bottles/frontend/ui/meson.build index 58d31f3761c..712f1ea9323 100644 --- a/bottles/frontend/ui/meson.build +++ b/bottles/frontend/ui/meson.build @@ -29,7 +29,7 @@ blueprints = custom_target('blueprints', 'upgrade-versioning-dialog.blp', 'vkbasalt-dialog.blp', 'display-dialog.blp', - 'dialog-vmtouch.blp', + 'vmtouch-dialog.blp', 'fsr-dialog.blp', 'mangohud-dialog.blp', 'dll-override-entry.blp', diff --git a/bottles/frontend/ui/dialog-vmtouch.blp b/bottles/frontend/ui/vmtouch-dialog.blp similarity index 100% rename from bottles/frontend/ui/dialog-vmtouch.blp rename to bottles/frontend/ui/vmtouch-dialog.blp diff --git a/bottles/frontend/views/details_preferences_page.py b/bottles/frontend/views/details_preferences_page.py index 57e82d2e139..f9d68e09d39 100644 --- a/bottles/frontend/views/details_preferences_page.py +++ b/bottles/frontend/views/details_preferences_page.py @@ -56,7 +56,7 @@ from bottles.frontend.windows.proton_alert_dialog import ProtonAlertDialog from bottles.frontend.windows.sandbox_dialog import SandboxDialog from bottles.frontend.windows.vkbasalt_dialog import VkBasaltDialog -from bottles.frontend.windows.vmtouch import VmtouchDialog +from bottles.frontend.windows.vmtouch_dialog import VmtouchDialog logging = Logger() diff --git a/bottles/frontend/windows/meson.build b/bottles/frontend/windows/meson.build index fb35209eb6f..bdef01666ac 100644 --- a/bottles/frontend/windows/meson.build +++ b/bottles/frontend/windows/meson.build @@ -26,7 +26,7 @@ bottles_sources = [ 'dependencies_check_dialog.py', 'exclusion_patterns_dialog.py', 'upgrade_versioning_dialog.py', - 'vmtouch.py', + 'vmtouch_dialog.py', 'window.py', ] diff --git a/bottles/frontend/windows/vmtouch.py b/bottles/frontend/windows/vmtouch_dialog.py similarity index 93% rename from bottles/frontend/windows/vmtouch.py rename to bottles/frontend/windows/vmtouch_dialog.py index b613dc23413..1560ee89e3e 100644 --- a/bottles/frontend/windows/vmtouch.py +++ b/bottles/frontend/windows/vmtouch_dialog.py @@ -1,6 +1,6 @@ -# vmtouch.py +# vmtouch_dialog.py # -# Copyright 2022 axtlos +# Copyright 2025 The Bottles Contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -20,7 +20,7 @@ from gi.repository import Gtk, GLib, Adw -@Gtk.Template(resource_path="/com/usebottles/bottles/dialog-vmtouch.ui") +@Gtk.Template(resource_path="/com/usebottles/bottles/vmtouch-dialog.ui") class VmtouchDialog(Adw.Window): __gtype_name__ = "VmtouchDialog" diff --git a/po/POTFILES b/po/POTFILES index 5c8aea01faf..8450e2eb125 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -29,6 +29,7 @@ bottles/frontend/ui/journal-dialog.blp bottles/frontend/ui/launch-options-dialog.blp bottles/frontend/ui/proton-alert-dialog.blp bottles/frontend/ui/rename-program-dialog.blp +bottles/frontend/ui/vmtouch-dialog.blp bottles/frontend/ui/sandbox-dialog.blp bottles/frontend/ui/upgrade-versioning-dialog.blp bottles/frontend/ui/vkbasalt-dialog.blp From 3838cd8ef792a60fca4a77aea2b162cb50eab0b7 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Thu, 16 Jan 2025 16:05:30 -0500 Subject: [PATCH 052/146] library-entry: Rename files --- bottles/frontend/views/library_view.py | 2 +- bottles/frontend/widgets/{library.py => library_entry.py} | 4 ++-- bottles/frontend/widgets/meson.build | 2 +- po/POTFILES | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) rename bottles/frontend/widgets/{library.py => library_entry.py} (99%) diff --git a/bottles/frontend/views/library_view.py b/bottles/frontend/views/library_view.py index 45cbf5ad80f..920bd20215d 100644 --- a/bottles/frontend/views/library_view.py +++ b/bottles/frontend/views/library_view.py @@ -22,7 +22,7 @@ from bottles.backend.managers.library import LibraryManager from bottles.frontend.utils.gtk import GtkUtils -from bottles.frontend.widgets.library import LibraryEntry +from bottles.frontend.widgets.library_entry import LibraryEntry @Gtk.Template(resource_path="/com/usebottles/bottles/library-view.ui") diff --git a/bottles/frontend/widgets/library.py b/bottles/frontend/widgets/library_entry.py similarity index 99% rename from bottles/frontend/widgets/library.py rename to bottles/frontend/widgets/library_entry.py index 88fe68eb240..99e2b983a25 100644 --- a/bottles/frontend/widgets/library.py +++ b/bottles/frontend/widgets/library_entry.py @@ -1,6 +1,6 @@ -# library.py +# library_entry.py # -# Copyright 2022 brombinmirko +# Copyright 2025 The Bottles Contributors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/bottles/frontend/widgets/meson.build b/bottles/frontend/widgets/meson.build index db12efc56d0..f13e4e3d68f 100644 --- a/bottles/frontend/widgets/meson.build +++ b/bottles/frontend/widgets/meson.build @@ -10,7 +10,7 @@ bottles_sources = [ 'program_row.py', 'state_row.py', 'component_entry_row.py', - 'library.py', + 'library_entry.py', ] install_data(bottles_sources, install_dir: widgetsdir) diff --git a/po/POTFILES b/po/POTFILES index 8450e2eb125..34bbbd2f3d7 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -69,7 +69,7 @@ bottles/frontend/widgets/component.py bottles/frontend/widgets/dependency.py bottles/frontend/widgets/importer_row.py bottles/frontend/widgets/installer_row.py -bottles/frontend/widgets/library.py +bottles/frontend/widgets/library_entry.py bottles/frontend/widgets/program_row.py bottles/frontend/widgets/state_row.py bottles/frontend/windows/crash_report_dialog.py From 468c6c6ad6842d9a5acd5c5a39f15ec5bbee14c8 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Mon, 13 Jan 2025 13:58:15 -0500 Subject: [PATCH 053/146] frontend: Move files to root of `frontend/` --- .../frontend/{ui => }/bottle-details-page.blp | 0 .../frontend/{ui => }/bottle-details-view.blp | 0 .../{ui => }/bottle-picker-dialog.blp | 0 bottles/frontend/{ui => }/bottle-row.blp | 0 .../{views => }/bottle_details_page.py | 12 +- .../{views => }/bottle_details_view.py | 14 +- .../{windows => }/bottle_picker_dialog.py | 0 .../frontend/{ui => }/bottles-list-view.blp | 0 .../frontend/{ui => }/bottles.gresource.xml | 0 .../frontend/{views => }/bottles_list_view.py | 2 +- bottles/frontend/{ui => }/check-row.blp | 0 bottles/frontend/{cli => }/cli.py | 0 bottles/frontend/cli/__init__.py | 0 bottles/frontend/cli/meson.build | 17 -- bottles/frontend/{utils => }/common.py | 0 .../frontend/{ui => }/component-entry-row.blp | 0 .../{widgets => }/component_entry_row.py | 2 +- .../frontend/{ui => }/crash-report-dialog.blp | 0 .../{windows => }/crash_report_dialog.py | 0 .../{ui => }/dependencies-check-dialog.blp | 0 .../dependencies_check_dialog.py | 0 .../{ui => }/dependency-entry-row.blp | 0 .../{widgets => }/dependency_entry_row.py | 4 +- .../{ui => }/details-dependencies-view.blp | 0 .../{ui => }/details-installers-view.blp | 0 .../{ui => }/details-preferences-page.blp | 0 .../{ui => }/details-task-manager-view.blp | 0 .../{ui => }/details-versioning-page.blp | 0 .../{views => }/details_dependencies_view.py | 6 +- .../{views => }/details_installers_view.py | 4 +- .../{views => }/details_preferences_page.py | 26 +-- .../{views => }/details_task_manager_view.py | 2 +- .../{views => }/details_versioning_page.py | 6 +- bottles/frontend/{ui => }/display-dialog.blp | 0 .../frontend/{windows => }/display_dialog.py | 2 +- .../frontend/{ui => }/dll-override-entry.blp | 0 .../{ui => }/dll-overrides-dialog.blp | 0 .../{windows => }/dll_overrides_dialog.py | 0 bottles/frontend/{ui => }/drive-entry.blp | 0 bottles/frontend/{ui => }/drives-dialog.blp | 0 .../frontend/{windows => }/drives_dialog.py | 0 .../frontend/{ui => }/duplicate-dialog.blp | 0 .../{windows => }/duplicate_dialog.py | 2 +- bottles/frontend/{ui => }/env-var-entry.blp | 0 .../{ui => }/environment-variables-dialog.blp | 0 .../environment_variables_dialog.py | 4 +- .../{ui => }/exclusion-pattern-row.blp | 0 .../{ui => }/exclusion-patterns-dialog.blp | 0 .../exclusion_patterns_dialog.py | 0 bottles/frontend/{widgets => }/executable.py | 0 bottles/frontend/{utils => }/filters.py | 0 bottles/frontend/{ui => }/fsr-dialog.blp | 0 bottles/frontend/{windows => }/fsr_dialog.py | 0 .../frontend/{ui => }/gamescope-dialog.blp | 0 .../{windows => }/gamescope_dialog.py | 0 bottles/frontend/{windows => }/generic.py | 0 bottles/frontend/{windows => }/generic_cli.py | 0 bottles/frontend/{utils => }/gtk.py | 2 +- bottles/frontend/{ui => }/help-overlay.blp | 0 bottles/frontend/{ui => }/importer-row.blp | 0 bottles/frontend/{ui => }/importer-view.blp | 0 .../frontend/{widgets => }/importer_row.py | 2 +- bottles/frontend/{views => }/importer_view.py | 6 +- .../frontend/{ui => }/installer-dialog.blp | 0 bottles/frontend/{ui => }/installer-row.blp | 0 .../{windows => }/installer_dialog.py | 2 +- .../frontend/{widgets => }/installer_row.py | 4 +- bottles/frontend/{ui => }/journal-dialog.blp | 0 .../frontend/{windows => }/journal_dialog.py | 0 .../{ui => }/launch-options-dialog.blp | 0 .../{windows => }/launch_options_dialog.py | 0 bottles/frontend/{ui => }/library-entry.blp | 0 bottles/frontend/{ui => }/library-view.blp | 0 .../frontend/{widgets => }/library_entry.py | 2 +- bottles/frontend/{views => }/library_view.py | 4 +- bottles/frontend/{ui => }/loading-view.blp | 0 bottles/frontend/{views => }/loading_view.py | 2 +- .../frontend/{ui => }/local-resource-row.blp | 0 bottles/frontend/main.py | 6 +- bottles/frontend/{ui => }/mangohud-dialog.blp | 0 .../frontend/{windows => }/mangohud_dialog.py | 0 bottles/frontend/meson.build | 143 ++++++++++++++-- .../frontend/{ui => }/new-bottle-dialog.blp | 0 .../frontend/{views => }/new_bottle_dialog.py | 4 +- bottles/frontend/{ui => }/onboard-dialog.blp | 0 .../frontend/{windows => }/onboard_dialog.py | 2 +- bottles/frontend/{ui => }/preferences.blp | 0 bottles/frontend/{views => }/preferences.py | 2 +- bottles/frontend/{ui => }/program-row.blp | 0 bottles/frontend/{widgets => }/program_row.py | 6 +- .../frontend/{ui => }/proton-alert-dialog.blp | 0 .../{windows => }/proton_alert_dialog.py | 0 .../{ui => }/rename-program-dialog.blp | 0 .../{windows => }/rename_program_dialog.py | 0 bottles/frontend/{ui => }/sandbox-dialog.blp | 0 .../frontend/{windows => }/sandbox_dialog.py | 0 bottles/frontend/{utils => }/sh.py | 0 bottles/frontend/{ui => }/state-row.blp | 0 bottles/frontend/{widgets => }/state_row.py | 2 +- bottles/frontend/{ui => }/style-dark.css | 0 bottles/frontend/{ui => }/style.css | 0 bottles/frontend/{ui => }/task-row.blp | 0 bottles/frontend/ui/meson.build | 67 -------- .../{ui => }/upgrade-versioning-dialog.blp | 0 .../upgrade_versioning_dialog.py | 0 bottles/frontend/utils/__init__.py | 0 bottles/frontend/utils/meson.build | 12 -- bottles/frontend/views/__init__.py | 0 bottles/frontend/views/meson.build | 22 --- bottles/frontend/{ui => }/vkbasalt-dialog.blp | 0 .../frontend/{windows => }/vkbasalt_dialog.py | 0 bottles/frontend/{ui => }/vmtouch-dialog.blp | 0 .../frontend/{windows => }/vmtouch_dialog.py | 0 bottles/frontend/widgets/__init__.py | 0 bottles/frontend/widgets/meson.build | 16 -- bottles/frontend/{ui => }/window.blp | 0 bottles/frontend/{windows => }/window.py | 22 +-- bottles/frontend/windows/__init__.py | 0 bottles/frontend/windows/meson.build | 33 ---- po/POTFILES | 160 +++++++++--------- 120 files changed, 288 insertions(+), 336 deletions(-) rename bottles/frontend/{ui => }/bottle-details-page.blp (100%) rename bottles/frontend/{ui => }/bottle-details-view.blp (100%) rename bottles/frontend/{ui => }/bottle-picker-dialog.blp (100%) rename bottles/frontend/{ui => }/bottle-row.blp (100%) rename bottles/frontend/{views => }/bottle_details_page.py (98%) rename bottles/frontend/{views => }/bottle_details_view.py (94%) rename bottles/frontend/{windows => }/bottle_picker_dialog.py (100%) rename bottles/frontend/{ui => }/bottles-list-view.blp (100%) rename bottles/frontend/{ui => }/bottles.gresource.xml (100%) rename bottles/frontend/{views => }/bottles_list_view.py (98%) rename bottles/frontend/{ui => }/check-row.blp (100%) rename bottles/frontend/{cli => }/cli.py (100%) delete mode 100644 bottles/frontend/cli/__init__.py delete mode 100644 bottles/frontend/cli/meson.build rename bottles/frontend/{utils => }/common.py (100%) rename bottles/frontend/{ui => }/component-entry-row.blp (100%) rename bottles/frontend/{widgets => }/component_entry_row.py (99%) rename bottles/frontend/{ui => }/crash-report-dialog.blp (100%) rename bottles/frontend/{windows => }/crash_report_dialog.py (100%) rename bottles/frontend/{ui => }/dependencies-check-dialog.blp (100%) rename bottles/frontend/{windows => }/dependencies_check_dialog.py (100%) rename bottles/frontend/{ui => }/dependency-entry-row.blp (100%) rename bottles/frontend/{widgets => }/dependency_entry_row.py (98%) rename bottles/frontend/{ui => }/details-dependencies-view.blp (100%) rename bottles/frontend/{ui => }/details-installers-view.blp (100%) rename bottles/frontend/{ui => }/details-preferences-page.blp (100%) rename bottles/frontend/{ui => }/details-task-manager-view.blp (100%) rename bottles/frontend/{ui => }/details-versioning-page.blp (100%) rename bottles/frontend/{views => }/details_dependencies_view.py (96%) rename bottles/frontend/{views => }/details_installers_view.py (97%) rename bottles/frontend/{views => }/details_preferences_page.py (97%) rename bottles/frontend/{views => }/details_task_manager_view.py (99%) rename bottles/frontend/{views => }/details_versioning_page.py (97%) rename bottles/frontend/{ui => }/display-dialog.blp (100%) rename bottles/frontend/{windows => }/display_dialog.py (99%) rename bottles/frontend/{ui => }/dll-override-entry.blp (100%) rename bottles/frontend/{ui => }/dll-overrides-dialog.blp (100%) rename bottles/frontend/{windows => }/dll_overrides_dialog.py (100%) rename bottles/frontend/{ui => }/drive-entry.blp (100%) rename bottles/frontend/{ui => }/drives-dialog.blp (100%) rename bottles/frontend/{windows => }/drives_dialog.py (100%) rename bottles/frontend/{ui => }/duplicate-dialog.blp (100%) rename bottles/frontend/{windows => }/duplicate_dialog.py (98%) rename bottles/frontend/{ui => }/env-var-entry.blp (100%) rename bottles/frontend/{ui => }/environment-variables-dialog.blp (100%) rename bottles/frontend/{windows => }/environment_variables_dialog.py (98%) rename bottles/frontend/{ui => }/exclusion-pattern-row.blp (100%) rename bottles/frontend/{ui => }/exclusion-patterns-dialog.blp (100%) rename bottles/frontend/{windows => }/exclusion_patterns_dialog.py (100%) rename bottles/frontend/{widgets => }/executable.py (100%) rename bottles/frontend/{utils => }/filters.py (100%) rename bottles/frontend/{ui => }/fsr-dialog.blp (100%) rename bottles/frontend/{windows => }/fsr_dialog.py (100%) rename bottles/frontend/{ui => }/gamescope-dialog.blp (100%) rename bottles/frontend/{windows => }/gamescope_dialog.py (100%) rename bottles/frontend/{windows => }/generic.py (100%) rename bottles/frontend/{windows => }/generic_cli.py (100%) rename bottles/frontend/{utils => }/gtk.py (98%) rename bottles/frontend/{ui => }/help-overlay.blp (100%) rename bottles/frontend/{ui => }/importer-row.blp (100%) rename bottles/frontend/{ui => }/importer-view.blp (100%) rename bottles/frontend/{widgets => }/importer_row.py (98%) rename bottles/frontend/{views => }/importer_view.py (96%) rename bottles/frontend/{ui => }/installer-dialog.blp (100%) rename bottles/frontend/{ui => }/installer-row.blp (100%) rename bottles/frontend/{windows => }/installer_dialog.py (99%) rename bottles/frontend/{widgets => }/installer_row.py (96%) rename bottles/frontend/{ui => }/journal-dialog.blp (100%) rename bottles/frontend/{windows => }/journal_dialog.py (100%) rename bottles/frontend/{ui => }/launch-options-dialog.blp (100%) rename bottles/frontend/{windows => }/launch_options_dialog.py (100%) rename bottles/frontend/{ui => }/library-entry.blp (100%) rename bottles/frontend/{ui => }/library-view.blp (100%) rename bottles/frontend/{widgets => }/library_entry.py (99%) rename bottles/frontend/{views => }/library_view.py (96%) rename bottles/frontend/{ui => }/loading-view.blp (100%) rename bottles/frontend/{views => }/loading_view.py (97%) rename bottles/frontend/{ui => }/local-resource-row.blp (100%) rename bottles/frontend/{ui => }/mangohud-dialog.blp (100%) rename bottles/frontend/{windows => }/mangohud_dialog.py (100%) rename bottles/frontend/{ui => }/new-bottle-dialog.blp (100%) rename bottles/frontend/{views => }/new_bottle_dialog.py (98%) rename bottles/frontend/{ui => }/onboard-dialog.blp (100%) rename bottles/frontend/{windows => }/onboard_dialog.py (99%) rename bottles/frontend/{ui => }/preferences.blp (100%) rename bottles/frontend/{views => }/preferences.py (99%) rename bottles/frontend/{ui => }/program-row.blp (100%) rename bottles/frontend/{widgets => }/program_row.py (98%) rename bottles/frontend/{ui => }/proton-alert-dialog.blp (100%) rename bottles/frontend/{windows => }/proton_alert_dialog.py (100%) rename bottles/frontend/{ui => }/rename-program-dialog.blp (100%) rename bottles/frontend/{windows => }/rename_program_dialog.py (100%) rename bottles/frontend/{ui => }/sandbox-dialog.blp (100%) rename bottles/frontend/{windows => }/sandbox_dialog.py (100%) rename bottles/frontend/{utils => }/sh.py (100%) rename bottles/frontend/{ui => }/state-row.blp (100%) rename bottles/frontend/{widgets => }/state_row.py (98%) rename bottles/frontend/{ui => }/style-dark.css (100%) rename bottles/frontend/{ui => }/style.css (100%) rename bottles/frontend/{ui => }/task-row.blp (100%) delete mode 100644 bottles/frontend/ui/meson.build rename bottles/frontend/{ui => }/upgrade-versioning-dialog.blp (100%) rename bottles/frontend/{windows => }/upgrade_versioning_dialog.py (100%) delete mode 100644 bottles/frontend/utils/__init__.py delete mode 100644 bottles/frontend/utils/meson.build delete mode 100644 bottles/frontend/views/__init__.py delete mode 100644 bottles/frontend/views/meson.build rename bottles/frontend/{ui => }/vkbasalt-dialog.blp (100%) rename bottles/frontend/{windows => }/vkbasalt_dialog.py (100%) rename bottles/frontend/{ui => }/vmtouch-dialog.blp (100%) rename bottles/frontend/{windows => }/vmtouch_dialog.py (100%) delete mode 100644 bottles/frontend/widgets/__init__.py delete mode 100644 bottles/frontend/widgets/meson.build rename bottles/frontend/{ui => }/window.blp (100%) rename bottles/frontend/{windows => }/window.py (95%) delete mode 100644 bottles/frontend/windows/__init__.py delete mode 100644 bottles/frontend/windows/meson.build diff --git a/bottles/frontend/ui/bottle-details-page.blp b/bottles/frontend/bottle-details-page.blp similarity index 100% rename from bottles/frontend/ui/bottle-details-page.blp rename to bottles/frontend/bottle-details-page.blp diff --git a/bottles/frontend/ui/bottle-details-view.blp b/bottles/frontend/bottle-details-view.blp similarity index 100% rename from bottles/frontend/ui/bottle-details-view.blp rename to bottles/frontend/bottle-details-view.blp diff --git a/bottles/frontend/ui/bottle-picker-dialog.blp b/bottles/frontend/bottle-picker-dialog.blp similarity index 100% rename from bottles/frontend/ui/bottle-picker-dialog.blp rename to bottles/frontend/bottle-picker-dialog.blp diff --git a/bottles/frontend/ui/bottle-row.blp b/bottles/frontend/bottle-row.blp similarity index 100% rename from bottles/frontend/ui/bottle-row.blp rename to bottles/frontend/bottle-row.blp diff --git a/bottles/frontend/views/bottle_details_page.py b/bottles/frontend/bottle_details_page.py similarity index 98% rename from bottles/frontend/views/bottle_details_page.py rename to bottles/frontend/bottle_details_page.py index 4c60ed69e45..fb01c96b773 100644 --- a/bottles/frontend/views/bottle_details_page.py +++ b/bottles/frontend/bottle_details_page.py @@ -38,12 +38,12 @@ from bottles.backend.wine.winecfg import WineCfg from bottles.backend.wine.winedbg import WineDbg from bottles.backend.wine.wineserver import WineServer -from bottles.frontend.utils.common import open_doc_url -from bottles.frontend.utils.filters import add_executable_filters, add_all_filters -from bottles.frontend.utils.gtk import GtkUtils -from bottles.frontend.widgets.program_row import ProgramRow -from bottles.frontend.windows.duplicate_dialog import DuplicateDialog -from bottles.frontend.windows.upgrade_versioning_dialog import UpgradeVersioningDialog +from bottles.frontend.common import open_doc_url +from bottles.frontend.filters import add_executable_filters, add_all_filters +from bottles.frontend.gtk import GtkUtils +from bottles.frontend.program_row import ProgramRow +from bottles.frontend.duplicate_dialog import DuplicateDialog +from bottles.frontend.upgrade_versioning_dialog import UpgradeVersioningDialog @Gtk.Template(resource_path="/com/usebottles/bottles/bottle-details-page.ui") diff --git a/bottles/frontend/views/bottle_details_view.py b/bottles/frontend/bottle_details_view.py similarity index 94% rename from bottles/frontend/views/bottle_details_view.py rename to bottles/frontend/bottle_details_view.py index 92285f2e80f..f1292ca3025 100644 --- a/bottles/frontend/views/bottle_details_view.py +++ b/bottles/frontend/bottle_details_view.py @@ -25,13 +25,13 @@ from bottles.backend.models.config import BottleConfig from bottles.backend.utils.threading import RunAsync -from bottles.frontend.utils.gtk import GtkUtils -from bottles.frontend.views.bottle_details_page import BottleDetailsPage -from bottles.frontend.views.details_installers_view import DetailsInstallersView -from bottles.frontend.views.details_dependencies_view import DetailsDependenciesView -from bottles.frontend.views.details_preferences_page import DetailsPreferencesPage -from bottles.frontend.views.details_versioning_page import DetailsVersioningPage -from bottles.frontend.views.details_task_manager_view import DetailsTaskManagerView +from bottles.frontend.gtk import GtkUtils +from bottles.frontend.bottle_details_page import BottleDetailsPage +from bottles.frontend.details_installers_view import DetailsInstallersView +from bottles.frontend.details_dependencies_view import DetailsDependenciesView +from bottles.frontend.details_preferences_page import DetailsPreferencesPage +from bottles.frontend.details_versioning_page import DetailsVersioningPage +from bottles.frontend.details_task_manager_view import DetailsTaskManagerView @Gtk.Template(resource_path="/com/usebottles/bottles/bottle-details-view.ui") diff --git a/bottles/frontend/windows/bottle_picker_dialog.py b/bottles/frontend/bottle_picker_dialog.py similarity index 100% rename from bottles/frontend/windows/bottle_picker_dialog.py rename to bottles/frontend/bottle_picker_dialog.py diff --git a/bottles/frontend/ui/bottles-list-view.blp b/bottles/frontend/bottles-list-view.blp similarity index 100% rename from bottles/frontend/ui/bottles-list-view.blp rename to bottles/frontend/bottles-list-view.blp diff --git a/bottles/frontend/ui/bottles.gresource.xml b/bottles/frontend/bottles.gresource.xml similarity index 100% rename from bottles/frontend/ui/bottles.gresource.xml rename to bottles/frontend/bottles.gresource.xml diff --git a/bottles/frontend/views/bottles_list_view.py b/bottles/frontend/bottles_list_view.py similarity index 98% rename from bottles/frontend/views/bottles_list_view.py rename to bottles/frontend/bottles_list_view.py index 75738fd48d3..e2cffa18c25 100644 --- a/bottles/frontend/views/bottles_list_view.py +++ b/bottles/frontend/bottles_list_view.py @@ -25,7 +25,7 @@ from bottles.backend.state import Signals, SignalManager from bottles.backend.utils.threading import RunAsync from bottles.backend.wine.executor import WineExecutor -from bottles.frontend.utils.filters import add_executable_filters, add_all_filters +from bottles.frontend.filters import add_executable_filters, add_all_filters from bottles.frontend.params import APP_ID diff --git a/bottles/frontend/ui/check-row.blp b/bottles/frontend/check-row.blp similarity index 100% rename from bottles/frontend/ui/check-row.blp rename to bottles/frontend/check-row.blp diff --git a/bottles/frontend/cli/cli.py b/bottles/frontend/cli.py similarity index 100% rename from bottles/frontend/cli/cli.py rename to bottles/frontend/cli.py diff --git a/bottles/frontend/cli/__init__.py b/bottles/frontend/cli/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/bottles/frontend/cli/meson.build b/bottles/frontend/cli/meson.build deleted file mode 100644 index b9eb81fb1a7..00000000000 --- a/bottles/frontend/cli/meson.build +++ /dev/null @@ -1,17 +0,0 @@ -pkgdatadir = join_paths(get_option('prefix'), get_option('datadir'), meson.project_name()) -clidir = join_paths(pkgdatadir, 'bottles/frontend/cli') - -bottles_sources = [ - '__init__.py', -] - -install_data(bottles_sources, install_dir: clidir) - -configure_file( - input: 'cli.py', - output: 'bottles-cli', - configuration: conf, - install: true, - install_dir: get_option('bindir'), - install_mode: ['rwxr-xr-x'] -) diff --git a/bottles/frontend/utils/common.py b/bottles/frontend/common.py similarity index 100% rename from bottles/frontend/utils/common.py rename to bottles/frontend/common.py diff --git a/bottles/frontend/ui/component-entry-row.blp b/bottles/frontend/component-entry-row.blp similarity index 100% rename from bottles/frontend/ui/component-entry-row.blp rename to bottles/frontend/component-entry-row.blp diff --git a/bottles/frontend/widgets/component_entry_row.py b/bottles/frontend/component_entry_row.py similarity index 99% rename from bottles/frontend/widgets/component_entry_row.py rename to bottles/frontend/component_entry_row.py index 5b7766b6a89..4175fa8c36c 100644 --- a/bottles/frontend/widgets/component_entry_row.py +++ b/bottles/frontend/component_entry_row.py @@ -24,7 +24,7 @@ from bottles.backend.state import Status from bottles.backend.utils.manager import ManagerUtils from bottles.backend.utils.threading import RunAsync -from bottles.frontend.utils.gtk import GtkUtils +from bottles.frontend.gtk import GtkUtils logging = Logger() diff --git a/bottles/frontend/ui/crash-report-dialog.blp b/bottles/frontend/crash-report-dialog.blp similarity index 100% rename from bottles/frontend/ui/crash-report-dialog.blp rename to bottles/frontend/crash-report-dialog.blp diff --git a/bottles/frontend/windows/crash_report_dialog.py b/bottles/frontend/crash_report_dialog.py similarity index 100% rename from bottles/frontend/windows/crash_report_dialog.py rename to bottles/frontend/crash_report_dialog.py diff --git a/bottles/frontend/ui/dependencies-check-dialog.blp b/bottles/frontend/dependencies-check-dialog.blp similarity index 100% rename from bottles/frontend/ui/dependencies-check-dialog.blp rename to bottles/frontend/dependencies-check-dialog.blp diff --git a/bottles/frontend/windows/dependencies_check_dialog.py b/bottles/frontend/dependencies_check_dialog.py similarity index 100% rename from bottles/frontend/windows/dependencies_check_dialog.py rename to bottles/frontend/dependencies_check_dialog.py diff --git a/bottles/frontend/ui/dependency-entry-row.blp b/bottles/frontend/dependency-entry-row.blp similarity index 100% rename from bottles/frontend/ui/dependency-entry-row.blp rename to bottles/frontend/dependency-entry-row.blp diff --git a/bottles/frontend/widgets/dependency_entry_row.py b/bottles/frontend/dependency_entry_row.py similarity index 98% rename from bottles/frontend/widgets/dependency_entry_row.py rename to bottles/frontend/dependency_entry_row.py index 3595926c75b..99646567f2e 100644 --- a/bottles/frontend/widgets/dependency_entry_row.py +++ b/bottles/frontend/dependency_entry_row.py @@ -24,8 +24,8 @@ from bottles.backend.models.config import BottleConfig from bottles.backend.models.result import Result from bottles.backend.utils.threading import RunAsync -from bottles.frontend.utils.gtk import GtkUtils -from bottles.frontend.windows.generic import SourceDialog +from bottles.frontend.gtk import GtkUtils +from bottles.frontend.generic import SourceDialog @Gtk.Template(resource_path="/com/usebottles/bottles/dependency-entry-row.ui") diff --git a/bottles/frontend/ui/details-dependencies-view.blp b/bottles/frontend/details-dependencies-view.blp similarity index 100% rename from bottles/frontend/ui/details-dependencies-view.blp rename to bottles/frontend/details-dependencies-view.blp diff --git a/bottles/frontend/ui/details-installers-view.blp b/bottles/frontend/details-installers-view.blp similarity index 100% rename from bottles/frontend/ui/details-installers-view.blp rename to bottles/frontend/details-installers-view.blp diff --git a/bottles/frontend/ui/details-preferences-page.blp b/bottles/frontend/details-preferences-page.blp similarity index 100% rename from bottles/frontend/ui/details-preferences-page.blp rename to bottles/frontend/details-preferences-page.blp diff --git a/bottles/frontend/ui/details-task-manager-view.blp b/bottles/frontend/details-task-manager-view.blp similarity index 100% rename from bottles/frontend/ui/details-task-manager-view.blp rename to bottles/frontend/details-task-manager-view.blp diff --git a/bottles/frontend/ui/details-versioning-page.blp b/bottles/frontend/details-versioning-page.blp similarity index 100% rename from bottles/frontend/ui/details-versioning-page.blp rename to bottles/frontend/details-versioning-page.blp diff --git a/bottles/frontend/views/details_dependencies_view.py b/bottles/frontend/details_dependencies_view.py similarity index 96% rename from bottles/frontend/views/details_dependencies_view.py rename to bottles/frontend/details_dependencies_view.py index e93bcea5c83..217ef84954f 100644 --- a/bottles/frontend/views/details_dependencies_view.py +++ b/bottles/frontend/details_dependencies_view.py @@ -23,9 +23,9 @@ from bottles.backend.models.config import BottleConfig from bottles.backend.state import EventManager, Events from bottles.backend.utils.threading import RunAsync -from bottles.frontend.utils.common import open_doc_url -from bottles.frontend.utils.gtk import GtkUtils -from bottles.frontend.widgets.dependency_entry_row import DependencyEntryRow +from bottles.frontend.common import open_doc_url +from bottles.frontend.gtk import GtkUtils +from bottles.frontend.dependency_entry_row import DependencyEntryRow @Gtk.Template(resource_path="/com/usebottles/bottles/details-dependencies-view.ui") diff --git a/bottles/frontend/views/details_installers_view.py b/bottles/frontend/details_installers_view.py similarity index 97% rename from bottles/frontend/views/details_installers_view.py rename to bottles/frontend/details_installers_view.py index cb74fd620d5..e6059475fd7 100644 --- a/bottles/frontend/views/details_installers_view.py +++ b/bottles/frontend/details_installers_view.py @@ -22,8 +22,8 @@ from bottles.backend.models.result import Result from bottles.backend.utils.threading import RunAsync -from bottles.frontend.utils.common import open_doc_url -from bottles.frontend.widgets.installer_row import InstallerRow +from bottles.frontend.common import open_doc_url +from bottles.frontend.installer_row import InstallerRow @Gtk.Template(resource_path="/com/usebottles/bottles/details-installers-view.ui") diff --git a/bottles/frontend/views/details_preferences_page.py b/bottles/frontend/details_preferences_page.py similarity index 97% rename from bottles/frontend/views/details_preferences_page.py rename to bottles/frontend/details_preferences_page.py index f9d68e09d39..ee89982dc75 100644 --- a/bottles/frontend/views/details_preferences_page.py +++ b/bottles/frontend/details_preferences_page.py @@ -42,21 +42,21 @@ from bottles.backend.utils.manager import ManagerUtils from bottles.backend.utils.threading import RunAsync from bottles.backend.wine.regkeys import RegKeys -from bottles.frontend.utils.gtk import GtkUtils -from bottles.frontend.windows.display_dialog import DisplayDialog -from bottles.frontend.windows.dll_overrides_dialog import DLLOverridesDialog -from bottles.frontend.windows.drives_dialog import DrivesDialog -from bottles.frontend.windows.environment_variables_dialog import ( +from bottles.frontend.gtk import GtkUtils +from bottles.frontend.display_dialog import DisplayDialog +from bottles.frontend.dll_overrides_dialog import DLLOverridesDialog +from bottles.frontend.drives_dialog import DrivesDialog +from bottles.frontend.environment_variables_dialog import ( EnvironmentVariablesDialog, ) -from bottles.frontend.windows.exclusion_patterns_dialog import ExclusionPatternsDialog -from bottles.frontend.windows.fsr_dialog import FsrDialog -from bottles.frontend.windows.gamescope_dialog import GamescopeDialog -from bottles.frontend.windows.mangohud_dialog import MangoHudDialog -from bottles.frontend.windows.proton_alert_dialog import ProtonAlertDialog -from bottles.frontend.windows.sandbox_dialog import SandboxDialog -from bottles.frontend.windows.vkbasalt_dialog import VkBasaltDialog -from bottles.frontend.windows.vmtouch_dialog import VmtouchDialog +from bottles.frontend.exclusion_patterns_dialog import ExclusionPatternsDialog +from bottles.frontend.fsr_dialog import FsrDialog +from bottles.frontend.gamescope_dialog import GamescopeDialog +from bottles.frontend.mangohud_dialog import MangoHudDialog +from bottles.frontend.proton_alert_dialog import ProtonAlertDialog +from bottles.frontend.sandbox_dialog import SandboxDialog +from bottles.frontend.vkbasalt_dialog import VkBasaltDialog +from bottles.frontend.vmtouch_dialog import VmtouchDialog logging = Logger() diff --git a/bottles/frontend/views/details_task_manager_view.py b/bottles/frontend/details_task_manager_view.py similarity index 99% rename from bottles/frontend/views/details_task_manager_view.py rename to bottles/frontend/details_task_manager_view.py index f2d6d25a7b9..af55ee80365 100644 --- a/bottles/frontend/views/details_task_manager_view.py +++ b/bottles/frontend/details_task_manager_view.py @@ -23,7 +23,7 @@ from bottles.backend.utils.threading import RunAsync from bottles.backend.wine.winebridge import WineBridge from bottles.backend.wine.winedbg import WineDbg -from bottles.frontend.utils.gtk import GtkUtils +from bottles.frontend.gtk import GtkUtils @Gtk.Template(resource_path="/com/usebottles/bottles/details-task-manager-view.ui") diff --git a/bottles/frontend/views/details_versioning_page.py b/bottles/frontend/details_versioning_page.py similarity index 97% rename from bottles/frontend/views/details_versioning_page.py rename to bottles/frontend/details_versioning_page.py index 661852d3f9c..d83408f3287 100644 --- a/bottles/frontend/views/details_versioning_page.py +++ b/bottles/frontend/details_versioning_page.py @@ -22,9 +22,9 @@ from bottles.backend.models.result import Result from bottles.backend.utils.threading import RunAsync -from bottles.frontend.utils.common import open_doc_url -from bottles.frontend.utils.gtk import GtkUtils -from bottles.frontend.widgets.state_row import StateRow +from bottles.frontend.common import open_doc_url +from bottles.frontend.gtk import GtkUtils +from bottles.frontend.state_row import StateRow @Gtk.Template(resource_path="/com/usebottles/bottles/details-versioning-page.ui") diff --git a/bottles/frontend/ui/display-dialog.blp b/bottles/frontend/display-dialog.blp similarity index 100% rename from bottles/frontend/ui/display-dialog.blp rename to bottles/frontend/display-dialog.blp diff --git a/bottles/frontend/windows/display_dialog.py b/bottles/frontend/display_dialog.py similarity index 99% rename from bottles/frontend/windows/display_dialog.py rename to bottles/frontend/display_dialog.py index 0d6ce738062..d5a605a3941 100644 --- a/bottles/frontend/windows/display_dialog.py +++ b/bottles/frontend/display_dialog.py @@ -23,7 +23,7 @@ from bottles.backend.utils.threading import RunAsync from bottles.backend.wine.reg import Reg from bottles.backend.wine.regkeys import RegKeys -from bottles.frontend.utils.gtk import GtkUtils +from bottles.frontend.gtk import GtkUtils logging = Logger() diff --git a/bottles/frontend/ui/dll-override-entry.blp b/bottles/frontend/dll-override-entry.blp similarity index 100% rename from bottles/frontend/ui/dll-override-entry.blp rename to bottles/frontend/dll-override-entry.blp diff --git a/bottles/frontend/ui/dll-overrides-dialog.blp b/bottles/frontend/dll-overrides-dialog.blp similarity index 100% rename from bottles/frontend/ui/dll-overrides-dialog.blp rename to bottles/frontend/dll-overrides-dialog.blp diff --git a/bottles/frontend/windows/dll_overrides_dialog.py b/bottles/frontend/dll_overrides_dialog.py similarity index 100% rename from bottles/frontend/windows/dll_overrides_dialog.py rename to bottles/frontend/dll_overrides_dialog.py diff --git a/bottles/frontend/ui/drive-entry.blp b/bottles/frontend/drive-entry.blp similarity index 100% rename from bottles/frontend/ui/drive-entry.blp rename to bottles/frontend/drive-entry.blp diff --git a/bottles/frontend/ui/drives-dialog.blp b/bottles/frontend/drives-dialog.blp similarity index 100% rename from bottles/frontend/ui/drives-dialog.blp rename to bottles/frontend/drives-dialog.blp diff --git a/bottles/frontend/windows/drives_dialog.py b/bottles/frontend/drives_dialog.py similarity index 100% rename from bottles/frontend/windows/drives_dialog.py rename to bottles/frontend/drives_dialog.py diff --git a/bottles/frontend/ui/duplicate-dialog.blp b/bottles/frontend/duplicate-dialog.blp similarity index 100% rename from bottles/frontend/ui/duplicate-dialog.blp rename to bottles/frontend/duplicate-dialog.blp diff --git a/bottles/frontend/windows/duplicate_dialog.py b/bottles/frontend/duplicate_dialog.py similarity index 98% rename from bottles/frontend/windows/duplicate_dialog.py rename to bottles/frontend/duplicate_dialog.py index 31c70539bbe..a3b839430de 100644 --- a/bottles/frontend/windows/duplicate_dialog.py +++ b/bottles/frontend/duplicate_dialog.py @@ -21,7 +21,7 @@ from bottles.backend.managers.backup import BackupManager from bottles.backend.utils.threading import RunAsync -from bottles.frontend.utils.gtk import GtkUtils +from bottles.frontend.gtk import GtkUtils @Gtk.Template(resource_path="/com/usebottles/bottles/duplicate-dialog.ui") diff --git a/bottles/frontend/ui/env-var-entry.blp b/bottles/frontend/env-var-entry.blp similarity index 100% rename from bottles/frontend/ui/env-var-entry.blp rename to bottles/frontend/env-var-entry.blp diff --git a/bottles/frontend/ui/environment-variables-dialog.blp b/bottles/frontend/environment-variables-dialog.blp similarity index 100% rename from bottles/frontend/ui/environment-variables-dialog.blp rename to bottles/frontend/environment-variables-dialog.blp diff --git a/bottles/frontend/windows/environment_variables_dialog.py b/bottles/frontend/environment_variables_dialog.py similarity index 98% rename from bottles/frontend/windows/environment_variables_dialog.py rename to bottles/frontend/environment_variables_dialog.py index 8ca9de36571..8252a135f0a 100644 --- a/bottles/frontend/windows/environment_variables_dialog.py +++ b/bottles/frontend/environment_variables_dialog.py @@ -20,8 +20,8 @@ from gi.repository import Gtk, GLib, Adw from bottles.backend.logger import Logger -from bottles.frontend.utils.gtk import GtkUtils -from bottles.frontend.utils.sh import ShUtils +from bottles.frontend.gtk import GtkUtils +from bottles.frontend.sh import ShUtils logging = Logger() diff --git a/bottles/frontend/ui/exclusion-pattern-row.blp b/bottles/frontend/exclusion-pattern-row.blp similarity index 100% rename from bottles/frontend/ui/exclusion-pattern-row.blp rename to bottles/frontend/exclusion-pattern-row.blp diff --git a/bottles/frontend/ui/exclusion-patterns-dialog.blp b/bottles/frontend/exclusion-patterns-dialog.blp similarity index 100% rename from bottles/frontend/ui/exclusion-patterns-dialog.blp rename to bottles/frontend/exclusion-patterns-dialog.blp diff --git a/bottles/frontend/windows/exclusion_patterns_dialog.py b/bottles/frontend/exclusion_patterns_dialog.py similarity index 100% rename from bottles/frontend/windows/exclusion_patterns_dialog.py rename to bottles/frontend/exclusion_patterns_dialog.py diff --git a/bottles/frontend/widgets/executable.py b/bottles/frontend/executable.py similarity index 100% rename from bottles/frontend/widgets/executable.py rename to bottles/frontend/executable.py diff --git a/bottles/frontend/utils/filters.py b/bottles/frontend/filters.py similarity index 100% rename from bottles/frontend/utils/filters.py rename to bottles/frontend/filters.py diff --git a/bottles/frontend/ui/fsr-dialog.blp b/bottles/frontend/fsr-dialog.blp similarity index 100% rename from bottles/frontend/ui/fsr-dialog.blp rename to bottles/frontend/fsr-dialog.blp diff --git a/bottles/frontend/windows/fsr_dialog.py b/bottles/frontend/fsr_dialog.py similarity index 100% rename from bottles/frontend/windows/fsr_dialog.py rename to bottles/frontend/fsr_dialog.py diff --git a/bottles/frontend/ui/gamescope-dialog.blp b/bottles/frontend/gamescope-dialog.blp similarity index 100% rename from bottles/frontend/ui/gamescope-dialog.blp rename to bottles/frontend/gamescope-dialog.blp diff --git a/bottles/frontend/windows/gamescope_dialog.py b/bottles/frontend/gamescope_dialog.py similarity index 100% rename from bottles/frontend/windows/gamescope_dialog.py rename to bottles/frontend/gamescope_dialog.py diff --git a/bottles/frontend/windows/generic.py b/bottles/frontend/generic.py similarity index 100% rename from bottles/frontend/windows/generic.py rename to bottles/frontend/generic.py diff --git a/bottles/frontend/windows/generic_cli.py b/bottles/frontend/generic_cli.py similarity index 100% rename from bottles/frontend/windows/generic_cli.py rename to bottles/frontend/generic_cli.py diff --git a/bottles/frontend/utils/gtk.py b/bottles/frontend/gtk.py similarity index 98% rename from bottles/frontend/utils/gtk.py rename to bottles/frontend/gtk.py index 3af520d6c37..dfad76e6552 100644 --- a/bottles/frontend/utils/gtk.py +++ b/bottles/frontend/gtk.py @@ -21,7 +21,7 @@ from gi.repository import GLib, Gtk, GObject -from bottles.frontend.utils.sh import ShUtils +from bottles.frontend.sh import ShUtils class GtkUtils: diff --git a/bottles/frontend/ui/help-overlay.blp b/bottles/frontend/help-overlay.blp similarity index 100% rename from bottles/frontend/ui/help-overlay.blp rename to bottles/frontend/help-overlay.blp diff --git a/bottles/frontend/ui/importer-row.blp b/bottles/frontend/importer-row.blp similarity index 100% rename from bottles/frontend/ui/importer-row.blp rename to bottles/frontend/importer-row.blp diff --git a/bottles/frontend/ui/importer-view.blp b/bottles/frontend/importer-view.blp similarity index 100% rename from bottles/frontend/ui/importer-view.blp rename to bottles/frontend/importer-view.blp diff --git a/bottles/frontend/widgets/importer_row.py b/bottles/frontend/importer_row.py similarity index 98% rename from bottles/frontend/widgets/importer_row.py rename to bottles/frontend/importer_row.py index 3fec3da5e46..106bb04af5a 100644 --- a/bottles/frontend/widgets/importer_row.py +++ b/bottles/frontend/importer_row.py @@ -21,7 +21,7 @@ from bottles.backend.utils.manager import ManagerUtils from bottles.backend.utils.threading import RunAsync -from bottles.frontend.utils.gtk import GtkUtils +from bottles.frontend.gtk import GtkUtils @Gtk.Template(resource_path="/com/usebottles/bottles/importer-row.ui") diff --git a/bottles/frontend/views/importer_view.py b/bottles/frontend/importer_view.py similarity index 96% rename from bottles/frontend/views/importer_view.py rename to bottles/frontend/importer_view.py index dfc50ecf18d..4a2256f2202 100644 --- a/bottles/frontend/views/importer_view.py +++ b/bottles/frontend/importer_view.py @@ -21,9 +21,9 @@ from bottles.backend.managers.backup import BackupManager from bottles.backend.utils.threading import RunAsync -from bottles.frontend.utils.filters import add_yaml_filters, add_all_filters -from bottles.frontend.utils.gtk import GtkUtils -from bottles.frontend.widgets.importer_row import ImporterRow +from bottles.frontend.filters import add_yaml_filters, add_all_filters +from bottles.frontend.gtk import GtkUtils +from bottles.frontend.importer_row import ImporterRow @Gtk.Template(resource_path="/com/usebottles/bottles/importer-view.ui") diff --git a/bottles/frontend/ui/installer-dialog.blp b/bottles/frontend/installer-dialog.blp similarity index 100% rename from bottles/frontend/ui/installer-dialog.blp rename to bottles/frontend/installer-dialog.blp diff --git a/bottles/frontend/ui/installer-row.blp b/bottles/frontend/installer-row.blp similarity index 100% rename from bottles/frontend/ui/installer-row.blp rename to bottles/frontend/installer-row.blp diff --git a/bottles/frontend/windows/installer_dialog.py b/bottles/frontend/installer_dialog.py similarity index 99% rename from bottles/frontend/windows/installer_dialog.py rename to bottles/frontend/installer_dialog.py index 9479c214e8a..775c1648ff8 100644 --- a/bottles/frontend/windows/installer_dialog.py +++ b/bottles/frontend/installer_dialog.py @@ -21,7 +21,7 @@ from gi.repository import Gtk, GLib, Gio, GdkPixbuf, Adw from bottles.backend.utils.threading import RunAsync -from bottles.frontend.utils.gtk import GtkUtils +from bottles.frontend.gtk import GtkUtils @Gtk.Template(resource_path="/com/usebottles/bottles/local-resource-row.ui") diff --git a/bottles/frontend/widgets/installer_row.py b/bottles/frontend/installer_row.py similarity index 96% rename from bottles/frontend/widgets/installer_row.py rename to bottles/frontend/installer_row.py index 6860dff9dc2..3e0d4906dfe 100644 --- a/bottles/frontend/widgets/installer_row.py +++ b/bottles/frontend/installer_row.py @@ -19,8 +19,8 @@ from gettext import gettext as _ import webbrowser -from bottles.frontend.windows.generic import SourceDialog -from bottles.frontend.windows.installer_dialog import InstallerDialog +from bottles.frontend.generic import SourceDialog +from bottles.frontend.installer_dialog import InstallerDialog @Gtk.Template(resource_path="/com/usebottles/bottles/installer-row.ui") diff --git a/bottles/frontend/ui/journal-dialog.blp b/bottles/frontend/journal-dialog.blp similarity index 100% rename from bottles/frontend/ui/journal-dialog.blp rename to bottles/frontend/journal-dialog.blp diff --git a/bottles/frontend/windows/journal_dialog.py b/bottles/frontend/journal_dialog.py similarity index 100% rename from bottles/frontend/windows/journal_dialog.py rename to bottles/frontend/journal_dialog.py diff --git a/bottles/frontend/ui/launch-options-dialog.blp b/bottles/frontend/launch-options-dialog.blp similarity index 100% rename from bottles/frontend/ui/launch-options-dialog.blp rename to bottles/frontend/launch-options-dialog.blp diff --git a/bottles/frontend/windows/launch_options_dialog.py b/bottles/frontend/launch_options_dialog.py similarity index 100% rename from bottles/frontend/windows/launch_options_dialog.py rename to bottles/frontend/launch_options_dialog.py diff --git a/bottles/frontend/ui/library-entry.blp b/bottles/frontend/library-entry.blp similarity index 100% rename from bottles/frontend/ui/library-entry.blp rename to bottles/frontend/library-entry.blp diff --git a/bottles/frontend/ui/library-view.blp b/bottles/frontend/library-view.blp similarity index 100% rename from bottles/frontend/ui/library-view.blp rename to bottles/frontend/library-view.blp diff --git a/bottles/frontend/widgets/library_entry.py b/bottles/frontend/library_entry.py similarity index 99% rename from bottles/frontend/widgets/library_entry.py rename to bottles/frontend/library_entry.py index 99e2b983a25..9679d98b746 100644 --- a/bottles/frontend/widgets/library_entry.py +++ b/bottles/frontend/library_entry.py @@ -26,7 +26,7 @@ from bottles.backend.utils.threading import RunAsync from bottles.backend.wine.executor import WineExecutor from bottles.backend.wine.winedbg import WineDbg -from bottles.frontend.utils.gtk import GtkUtils +from bottles.frontend.gtk import GtkUtils logging = Logger() diff --git a/bottles/frontend/views/library_view.py b/bottles/frontend/library_view.py similarity index 96% rename from bottles/frontend/views/library_view.py rename to bottles/frontend/library_view.py index 920bd20215d..c3cba16347b 100644 --- a/bottles/frontend/views/library_view.py +++ b/bottles/frontend/library_view.py @@ -21,8 +21,8 @@ from gi.repository import Gtk, Adw, GObject from bottles.backend.managers.library import LibraryManager -from bottles.frontend.utils.gtk import GtkUtils -from bottles.frontend.widgets.library_entry import LibraryEntry +from bottles.frontend.gtk import GtkUtils +from bottles.frontend.library_entry import LibraryEntry @Gtk.Template(resource_path="/com/usebottles/bottles/library-view.ui") diff --git a/bottles/frontend/ui/loading-view.blp b/bottles/frontend/loading-view.blp similarity index 100% rename from bottles/frontend/ui/loading-view.blp rename to bottles/frontend/loading-view.blp diff --git a/bottles/frontend/views/loading_view.py b/bottles/frontend/loading_view.py similarity index 97% rename from bottles/frontend/views/loading_view.py rename to bottles/frontend/loading_view.py index 36c44d585f2..330f26ac469 100644 --- a/bottles/frontend/views/loading_view.py +++ b/bottles/frontend/loading_view.py @@ -21,7 +21,7 @@ from bottles.backend.models.result import Result from bottles.backend.state import SignalManager, Signals -from bottles.frontend.utils.gtk import GtkUtils +from bottles.frontend.gtk import GtkUtils from bottles.frontend.params import APP_ID diff --git a/bottles/frontend/ui/local-resource-row.blp b/bottles/frontend/local-resource-row.blp similarity index 100% rename from bottles/frontend/ui/local-resource-row.blp rename to bottles/frontend/local-resource-row.blp diff --git a/bottles/frontend/main.py b/bottles/frontend/main.py index e5019150ab4..35855da8726 100644 --- a/bottles/frontend/main.py +++ b/bottles/frontend/main.py @@ -39,8 +39,8 @@ # ruff: noqa: E402 from gi.repository import Gio, GLib, GObject, Adw # type: ignore -from bottles.frontend.windows.window import BottlesWindow -from bottles.frontend.views.preferences import PreferencesWindow +from bottles.frontend.window import BottlesWindow +from bottles.frontend.preferences import PreferencesWindow logging = Logger() @@ -222,7 +222,7 @@ def __process_uri(self, uri): return 0 try: - from bottles.frontend.windows.bottle_picker_dialog import BottlePickerDialog + from bottles.frontend.bottle_picker_dialog import BottlePickerDialog dialog = BottlePickerDialog(application=self, arg_exe=uri) dialog.present() diff --git a/bottles/frontend/ui/mangohud-dialog.blp b/bottles/frontend/mangohud-dialog.blp similarity index 100% rename from bottles/frontend/ui/mangohud-dialog.blp rename to bottles/frontend/mangohud-dialog.blp diff --git a/bottles/frontend/windows/mangohud_dialog.py b/bottles/frontend/mangohud_dialog.py similarity index 100% rename from bottles/frontend/windows/mangohud_dialog.py rename to bottles/frontend/mangohud_dialog.py diff --git a/bottles/frontend/meson.build b/bottles/frontend/meson.build index 6ff7c011063..5bf84dd5d2c 100644 --- a/bottles/frontend/meson.build +++ b/bottles/frontend/meson.build @@ -1,12 +1,87 @@ pkgdatadir = join_paths(get_option('prefix'), get_option('datadir'), meson.project_name()) frontenddir = join_paths(pkgdatadir, 'bottles/frontend') -subdir('ui') -subdir('utils') -subdir('views') -subdir('widgets') -subdir('windows') -subdir('cli') +fs = import('fs') + +if not fs.is_file('/' + '.flatpak-info') + error('file does not exist') +endif + +gnome = import('gnome') +blueprints = custom_target('blueprints', + input: files( + 'component-entry-row.blp', + 'check-row.blp', + 'dependency-entry-row.blp', + 'bottle-details-page.blp', + 'details-dependencies-view.blp', + 'details-installers-view.blp', + 'details-task-manager-view.blp', + 'details-versioning-page.blp', + 'bottle-details-view.blp', + 'bottle-picker-dialog.blp', + 'crash-report-dialog.blp', + 'dependencies-check-dialog.blp', + 'dll-overrides-dialog.blp', + 'drives-dialog.blp', + 'duplicate-dialog.blp', + 'environment-variables-dialog.blp', + 'exclusion-patterns-dialog.blp', + 'gamescope-dialog.blp', + 'installer-dialog.blp', + 'journal-dialog.blp', + 'launch-options-dialog.blp', + 'proton-alert-dialog.blp', + 'rename-program-dialog.blp', + 'sandbox-dialog.blp', + 'upgrade-versioning-dialog.blp', + 'vkbasalt-dialog.blp', + 'display-dialog.blp', + 'vmtouch-dialog.blp', + 'fsr-dialog.blp', + 'mangohud-dialog.blp', + 'dll-override-entry.blp', + 'drive-entry.blp', + 'env-var-entry.blp', + 'exclusion-pattern-row.blp', + 'importer-row.blp', + 'importer-view.blp', + 'installer-row.blp', + 'library-entry.blp', + 'library-view.blp', + 'bottle-row.blp', + 'bottles-list-view.blp', + 'loading-view.blp', + 'local-resource-row.blp', + 'new-bottle-dialog.blp', + 'onboard-dialog.blp', + 'preferences.blp', + 'program-row.blp', + 'state-row.blp', + 'task-row.blp', + 'window.blp', + 'details-preferences-page.blp', + 'help-overlay.blp', + ), + output: '.', + command: [find_program('blueprint-compiler'), 'batch-compile', '@OUTPUT@', '@CURRENT_SOURCE_DIR@', '@INPUT@'],) + +gnome.compile_resources('bottles', + 'bottles.gresource.xml', + gresource_bundle: true, + dependencies: blueprints, + install: true, + install_dir: pkgdatadir, +) + +configure_file( + input: 'cli.py', + output: 'bottles-cli', + configuration: conf, + install: true, + install_dir: get_option('bindir'), + install_mode: ['rwxr-xr-x'] +) configure_file( input: 'bottles.py', @@ -23,16 +98,60 @@ params_file = configure_file( configuration: conf ) -fs = import('fs') - -if not fs.is_file('/' + '.flatpak-info') - error('file does not exist') -endif - bottles_sources = [ '__init__.py', 'main.py', 'operation.py', + 'gtk.py', + 'common.py', + 'filters.py', + 'sh.py', + 'new_bottle_dialog.py', + 'bottles_list_view.py', + 'library_view.py', + 'bottle_details_view.py', + 'preferences.py', + 'importer_view.py', + 'loading_view.py', + 'bottle_details_page.py', + 'details_installers_view.py', + 'details_dependencies_view.py', + 'details_preferences_page.py', + 'details_versioning_page.py', + 'details_task_manager_view.py', + 'dependency_entry_row.py', + 'executable.py', + 'importer_row.py', + 'installer_row.py', + 'program_row.py', + 'state_row.py', + 'component_entry_row.py', + 'library_entry.py', + 'crash_report_dialog.py', + 'dll_overrides_dialog.py', + 'duplicate_dialog.py', + 'environment_variables_dialog.py', + 'generic.py', + 'launch_options_dialog.py', + 'onboard_dialog.py', + 'rename_program_dialog.py', + 'drives_dialog.py', + 'gamescope_dialog.py', + 'vkbasalt_dialog.py', + 'fsr_dialog.py', + 'mangohud_dialog.py', + 'display_dialog.py', + 'generic_cli.py', + 'journal_dialog.py', + 'bottle_picker_dialog.py', + 'proton_alert_dialog.py', + 'sandbox_dialog.py', + 'installer_dialog.py', + 'dependencies_check_dialog.py', + 'exclusion_patterns_dialog.py', + 'upgrade_versioning_dialog.py', + 'vmtouch_dialog.py', + 'window.py', params_file, ] diff --git a/bottles/frontend/ui/new-bottle-dialog.blp b/bottles/frontend/new-bottle-dialog.blp similarity index 100% rename from bottles/frontend/ui/new-bottle-dialog.blp rename to bottles/frontend/new-bottle-dialog.blp diff --git a/bottles/frontend/views/new_bottle_dialog.py b/bottles/frontend/new_bottle_dialog.py similarity index 98% rename from bottles/frontend/views/new_bottle_dialog.py rename to bottles/frontend/new_bottle_dialog.py index 82fafa2d260..65718cb799f 100644 --- a/bottles/frontend/views/new_bottle_dialog.py +++ b/bottles/frontend/new_bottle_dialog.py @@ -22,8 +22,8 @@ from bottles.backend.models.config import BottleConfig from bottles.backend.utils.threading import RunAsync from bottles.backend.models.result import Result -from bottles.frontend.utils.filters import add_yaml_filters, add_all_filters -from bottles.frontend.utils.gtk import GtkUtils +from bottles.frontend.filters import add_yaml_filters, add_all_filters +from bottles.frontend.gtk import GtkUtils @Gtk.Template(resource_path="/com/usebottles/bottles/check-row.ui") diff --git a/bottles/frontend/ui/onboard-dialog.blp b/bottles/frontend/onboard-dialog.blp similarity index 100% rename from bottles/frontend/ui/onboard-dialog.blp rename to bottles/frontend/onboard-dialog.blp diff --git a/bottles/frontend/windows/onboard_dialog.py b/bottles/frontend/onboard_dialog.py similarity index 99% rename from bottles/frontend/windows/onboard_dialog.py rename to bottles/frontend/onboard_dialog.py index 076e36a8124..b5383f0e4b5 100644 --- a/bottles/frontend/windows/onboard_dialog.py +++ b/bottles/frontend/onboard_dialog.py @@ -21,7 +21,7 @@ from bottles.backend.models.result import Result from bottles.backend.utils.threading import RunAsync -from bottles.frontend.utils.gtk import GtkUtils +from bottles.frontend.gtk import GtkUtils @Gtk.Template(resource_path="/com/usebottles/bottles/onboard-dialog.ui") diff --git a/bottles/frontend/ui/preferences.blp b/bottles/frontend/preferences.blp similarity index 100% rename from bottles/frontend/ui/preferences.blp rename to bottles/frontend/preferences.blp diff --git a/bottles/frontend/views/preferences.py b/bottles/frontend/preferences.py similarity index 99% rename from bottles/frontend/views/preferences.py rename to bottles/frontend/preferences.py index aa214672cdf..3fe92492773 100644 --- a/bottles/frontend/views/preferences.py +++ b/bottles/frontend/preferences.py @@ -26,7 +26,7 @@ from bottles.backend.state import EventManager, Events from bottles.backend.utils.threading import RunAsync from bottles.backend.utils.generic import sort_by_version -from bottles.frontend.widgets.component_entry_row import ( +from bottles.frontend.component_entry_row import ( ComponentEntryRow, ComponentExpander, ) diff --git a/bottles/frontend/ui/program-row.blp b/bottles/frontend/program-row.blp similarity index 100% rename from bottles/frontend/ui/program-row.blp rename to bottles/frontend/program-row.blp diff --git a/bottles/frontend/widgets/program_row.py b/bottles/frontend/program_row.py similarity index 98% rename from bottles/frontend/widgets/program_row.py rename to bottles/frontend/program_row.py index da602c4ac0f..620cd041e57 100644 --- a/bottles/frontend/widgets/program_row.py +++ b/bottles/frontend/program_row.py @@ -28,9 +28,9 @@ from bottles.backend.wine.executor import WineExecutor from bottles.backend.wine.uninstaller import Uninstaller from bottles.backend.wine.winedbg import WineDbg -from bottles.frontend.utils.gtk import GtkUtils -from bottles.frontend.windows.launch_options_dialog import LaunchOptionsDialog -from bottles.frontend.windows.rename_program_dialog import RenameProgramDialog +from bottles.frontend.gtk import GtkUtils +from bottles.frontend.launch_options_dialog import LaunchOptionsDialog +from bottles.frontend.rename_program_dialog import RenameProgramDialog # noinspection PyUnusedLocal diff --git a/bottles/frontend/ui/proton-alert-dialog.blp b/bottles/frontend/proton-alert-dialog.blp similarity index 100% rename from bottles/frontend/ui/proton-alert-dialog.blp rename to bottles/frontend/proton-alert-dialog.blp diff --git a/bottles/frontend/windows/proton_alert_dialog.py b/bottles/frontend/proton_alert_dialog.py similarity index 100% rename from bottles/frontend/windows/proton_alert_dialog.py rename to bottles/frontend/proton_alert_dialog.py diff --git a/bottles/frontend/ui/rename-program-dialog.blp b/bottles/frontend/rename-program-dialog.blp similarity index 100% rename from bottles/frontend/ui/rename-program-dialog.blp rename to bottles/frontend/rename-program-dialog.blp diff --git a/bottles/frontend/windows/rename_program_dialog.py b/bottles/frontend/rename_program_dialog.py similarity index 100% rename from bottles/frontend/windows/rename_program_dialog.py rename to bottles/frontend/rename_program_dialog.py diff --git a/bottles/frontend/ui/sandbox-dialog.blp b/bottles/frontend/sandbox-dialog.blp similarity index 100% rename from bottles/frontend/ui/sandbox-dialog.blp rename to bottles/frontend/sandbox-dialog.blp diff --git a/bottles/frontend/windows/sandbox_dialog.py b/bottles/frontend/sandbox_dialog.py similarity index 100% rename from bottles/frontend/windows/sandbox_dialog.py rename to bottles/frontend/sandbox_dialog.py diff --git a/bottles/frontend/utils/sh.py b/bottles/frontend/sh.py similarity index 100% rename from bottles/frontend/utils/sh.py rename to bottles/frontend/sh.py diff --git a/bottles/frontend/ui/state-row.blp b/bottles/frontend/state-row.blp similarity index 100% rename from bottles/frontend/ui/state-row.blp rename to bottles/frontend/state-row.blp diff --git a/bottles/frontend/widgets/state_row.py b/bottles/frontend/state_row.py similarity index 98% rename from bottles/frontend/widgets/state_row.py rename to bottles/frontend/state_row.py index 6f3c0f26faf..35e1f654a33 100644 --- a/bottles/frontend/widgets/state_row.py +++ b/bottles/frontend/state_row.py @@ -21,7 +21,7 @@ from gi.repository import Gtk, Adw from bottles.backend.utils.threading import RunAsync -from bottles.frontend.utils.gtk import GtkUtils +from bottles.frontend.gtk import GtkUtils @Gtk.Template(resource_path="/com/usebottles/bottles/state-row.ui") diff --git a/bottles/frontend/ui/style-dark.css b/bottles/frontend/style-dark.css similarity index 100% rename from bottles/frontend/ui/style-dark.css rename to bottles/frontend/style-dark.css diff --git a/bottles/frontend/ui/style.css b/bottles/frontend/style.css similarity index 100% rename from bottles/frontend/ui/style.css rename to bottles/frontend/style.css diff --git a/bottles/frontend/ui/task-row.blp b/bottles/frontend/task-row.blp similarity index 100% rename from bottles/frontend/ui/task-row.blp rename to bottles/frontend/task-row.blp diff --git a/bottles/frontend/ui/meson.build b/bottles/frontend/ui/meson.build deleted file mode 100644 index 712f1ea9323..00000000000 --- a/bottles/frontend/ui/meson.build +++ /dev/null @@ -1,67 +0,0 @@ -pkgdatadir = join_paths(get_option('prefix'), get_option('datadir'), meson.project_name()) -gnome = import('gnome') -blueprints = custom_target('blueprints', - input: files( - 'component-entry-row.blp', - 'check-row.blp', - 'dependency-entry-row.blp', - 'bottle-details-page.blp', - 'details-dependencies-view.blp', - 'details-installers-view.blp', - 'details-task-manager-view.blp', - 'details-versioning-page.blp', - 'bottle-details-view.blp', - 'bottle-picker-dialog.blp', - 'crash-report-dialog.blp', - 'dependencies-check-dialog.blp', - 'dll-overrides-dialog.blp', - 'drives-dialog.blp', - 'duplicate-dialog.blp', - 'environment-variables-dialog.blp', - 'exclusion-patterns-dialog.blp', - 'gamescope-dialog.blp', - 'installer-dialog.blp', - 'journal-dialog.blp', - 'launch-options-dialog.blp', - 'proton-alert-dialog.blp', - 'rename-program-dialog.blp', - 'sandbox-dialog.blp', - 'upgrade-versioning-dialog.blp', - 'vkbasalt-dialog.blp', - 'display-dialog.blp', - 'vmtouch-dialog.blp', - 'fsr-dialog.blp', - 'mangohud-dialog.blp', - 'dll-override-entry.blp', - 'drive-entry.blp', - 'env-var-entry.blp', - 'exclusion-pattern-row.blp', - 'importer-row.blp', - 'importer-view.blp', - 'installer-row.blp', - 'library-entry.blp', - 'library-view.blp', - 'bottle-row.blp', - 'bottles-list-view.blp', - 'loading-view.blp', - 'local-resource-row.blp', - 'new-bottle-dialog.blp', - 'onboard-dialog.blp', - 'preferences.blp', - 'program-row.blp', - 'state-row.blp', - 'task-row.blp', - 'window.blp', - 'details-preferences-page.blp', - 'help-overlay.blp', - ), - output: '.', - command: [find_program('blueprint-compiler'), 'batch-compile', '@OUTPUT@', '@CURRENT_SOURCE_DIR@', '@INPUT@'],) - -gnome.compile_resources('bottles', - 'bottles.gresource.xml', - gresource_bundle: true, - dependencies: blueprints, - install: true, - install_dir: pkgdatadir, -) diff --git a/bottles/frontend/ui/upgrade-versioning-dialog.blp b/bottles/frontend/upgrade-versioning-dialog.blp similarity index 100% rename from bottles/frontend/ui/upgrade-versioning-dialog.blp rename to bottles/frontend/upgrade-versioning-dialog.blp diff --git a/bottles/frontend/windows/upgrade_versioning_dialog.py b/bottles/frontend/upgrade_versioning_dialog.py similarity index 100% rename from bottles/frontend/windows/upgrade_versioning_dialog.py rename to bottles/frontend/upgrade_versioning_dialog.py diff --git a/bottles/frontend/utils/__init__.py b/bottles/frontend/utils/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/bottles/frontend/utils/meson.build b/bottles/frontend/utils/meson.build deleted file mode 100644 index 5b280588e02..00000000000 --- a/bottles/frontend/utils/meson.build +++ /dev/null @@ -1,12 +0,0 @@ -pkgdatadir = join_paths(get_option('prefix'), get_option('datadir'), meson.project_name()) -utilsdir = join_paths(pkgdatadir, 'bottles/frontend/utils') - -bottles_sources = [ - '__init__.py', - 'gtk.py', - 'common.py', - 'filters.py', - 'sh.py', -] - -install_data(bottles_sources, install_dir: utilsdir) diff --git a/bottles/frontend/views/__init__.py b/bottles/frontend/views/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/bottles/frontend/views/meson.build b/bottles/frontend/views/meson.build deleted file mode 100644 index f856cda06ab..00000000000 --- a/bottles/frontend/views/meson.build +++ /dev/null @@ -1,22 +0,0 @@ -pkgdatadir = join_paths(get_option('prefix'), get_option('datadir'), meson.project_name()) -viewsdir = join_paths(pkgdatadir, 'bottles/frontend/views') - -bottles_sources = [ - '__init__.py', - 'new_bottle_dialog.py', - 'bottles_list_view.py', - 'library_view.py', - 'bottle_details_view.py', - 'preferences.py', - 'importer_view.py', - 'loading_view.py', - - 'bottle_details_page.py', - 'details_installers_view.py', - 'details_dependencies_view.py', - 'details_preferences_page.py', - 'details_versioning_page.py', - 'details_task_manager_view.py' -] - -install_data(bottles_sources, install_dir: viewsdir) diff --git a/bottles/frontend/ui/vkbasalt-dialog.blp b/bottles/frontend/vkbasalt-dialog.blp similarity index 100% rename from bottles/frontend/ui/vkbasalt-dialog.blp rename to bottles/frontend/vkbasalt-dialog.blp diff --git a/bottles/frontend/windows/vkbasalt_dialog.py b/bottles/frontend/vkbasalt_dialog.py similarity index 100% rename from bottles/frontend/windows/vkbasalt_dialog.py rename to bottles/frontend/vkbasalt_dialog.py diff --git a/bottles/frontend/ui/vmtouch-dialog.blp b/bottles/frontend/vmtouch-dialog.blp similarity index 100% rename from bottles/frontend/ui/vmtouch-dialog.blp rename to bottles/frontend/vmtouch-dialog.blp diff --git a/bottles/frontend/windows/vmtouch_dialog.py b/bottles/frontend/vmtouch_dialog.py similarity index 100% rename from bottles/frontend/windows/vmtouch_dialog.py rename to bottles/frontend/vmtouch_dialog.py diff --git a/bottles/frontend/widgets/__init__.py b/bottles/frontend/widgets/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/bottles/frontend/widgets/meson.build b/bottles/frontend/widgets/meson.build deleted file mode 100644 index f13e4e3d68f..00000000000 --- a/bottles/frontend/widgets/meson.build +++ /dev/null @@ -1,16 +0,0 @@ -pkgdatadir = join_paths(get_option('prefix'), get_option('datadir'), meson.project_name()) -widgetsdir = join_paths(pkgdatadir, 'bottles/frontend/widgets') - -bottles_sources = [ - '__init__.py', - 'dependency_entry_row.py', - 'executable.py', - 'importer_row.py', - 'installer_row.py', - 'program_row.py', - 'state_row.py', - 'component_entry_row.py', - 'library_entry.py', -] - -install_data(bottles_sources, install_dir: widgetsdir) diff --git a/bottles/frontend/ui/window.blp b/bottles/frontend/window.blp similarity index 100% rename from bottles/frontend/ui/window.blp rename to bottles/frontend/window.blp diff --git a/bottles/frontend/windows/window.py b/bottles/frontend/window.py similarity index 95% rename from bottles/frontend/windows/window.py rename to bottles/frontend/window.py index eb85e427b99..8e05ab88f91 100644 --- a/bottles/frontend/windows/window.py +++ b/bottles/frontend/window.py @@ -35,17 +35,17 @@ from bottles.backend.utils.threading import RunAsync from bottles.frontend.operation import TaskSyncer from bottles.frontend.params import APP_ID, BASE_ID, PROFILE -from bottles.frontend.utils.gtk import GtkUtils -from bottles.frontend.views.bottle_details_view import BottleDetailsView -from bottles.frontend.views.importer_view import ImporterView -from bottles.frontend.views.library_view import LibraryView -from bottles.frontend.views.bottles_list_view import BottlesListView -from bottles.frontend.views.loading_view import LoadingView -from bottles.frontend.views.new_bottle_dialog import NewBottleDialog -from bottles.frontend.views.preferences import PreferencesWindow -from bottles.frontend.windows.crash_report_dialog import CrashReportDialog -from bottles.frontend.windows.dependencies_check_dialog import DependenciesCheckDialog -from bottles.frontend.windows.onboard_dialog import OnboardDialog +from bottles.frontend.gtk import GtkUtils +from bottles.frontend.bottle_details_view import BottleDetailsView +from bottles.frontend.importer_view import ImporterView +from bottles.frontend.library_view import LibraryView +from bottles.frontend.bottles_list_view import BottlesListView +from bottles.frontend.loading_view import LoadingView +from bottles.frontend.new_bottle_dialog import NewBottleDialog +from bottles.frontend.preferences import PreferencesWindow +from bottles.frontend.crash_report_dialog import CrashReportDialog +from bottles.frontend.dependencies_check_dialog import DependenciesCheckDialog +from bottles.frontend.onboard_dialog import OnboardDialog logging = Logger() diff --git a/bottles/frontend/windows/__init__.py b/bottles/frontend/windows/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/bottles/frontend/windows/meson.build b/bottles/frontend/windows/meson.build deleted file mode 100644 index bdef01666ac..00000000000 --- a/bottles/frontend/windows/meson.build +++ /dev/null @@ -1,33 +0,0 @@ -pkgdatadir = join_paths(get_option('prefix'), get_option('datadir'), meson.project_name()) -dialogsdir = join_paths(pkgdatadir, 'bottles/frontend/windows') - -bottles_sources = [ - '__init__.py', - 'crash_report_dialog.py', - 'dll_overrides_dialog.py', - 'duplicate_dialog.py', - 'environment_variables_dialog.py', - 'generic.py', - 'launch_options_dialog.py', - 'onboard_dialog.py', - 'rename_program_dialog.py', - 'drives_dialog.py', - 'gamescope_dialog.py', - 'vkbasalt_dialog.py', - 'fsr_dialog.py', - 'mangohud_dialog.py', - 'display_dialog.py', - 'generic_cli.py', - 'journal_dialog.py', - 'bottle_picker_dialog.py', - 'proton_alert_dialog.py', - 'sandbox_dialog.py', - 'installer_dialog.py', - 'dependencies_check_dialog.py', - 'exclusion_patterns_dialog.py', - 'upgrade_versioning_dialog.py', - 'vmtouch_dialog.py', - 'window.py', -] - -install_data(bottles_sources, install_dir: dialogsdir) diff --git a/po/POTFILES b/po/POTFILES index 34bbbd2f3d7..7ed001f58d6 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -5,86 +5,86 @@ bottles/backend/managers/manager.py bottles/backend/managers/versioning.py bottles/frontend/main.py bottles/frontend/operation.py -bottles/frontend/ui/about.blp -bottles/frontend/ui/component-entry-row.blp -bottles/frontend/ui/dependency-entry-row.blp -bottles/frontend/ui/bottle-details-page.blp -bottles/frontend/ui/details-dependencies-view.blp -bottles/frontend/ui/details-installers-view.blp -bottles/frontend/ui/details-preferences-page.blp -bottles/frontend/ui/details-task-manager-view.blp -bottles/frontend/ui/details-versioning-page.blp -bottles/frontend/ui/bottle-details-view.blp -bottles/frontend/ui/bottle-picker-dialog.blp -bottles/frontend/ui/crash-report-dialog.blp -bottles/frontend/ui/dependencies-check-dialog.blp -bottles/frontend/ui/dll-overrides-dialog.blp -bottles/frontend/ui/drives-dialog.blp -bottles/frontend/ui/duplicate-dialog.blp -bottles/frontend/ui/environment-variables-dialog.blp -bottles/frontend/ui/exclusion-patterns-dialog.blp -bottles/frontend/ui/gamescope-dialog.blp -bottles/frontend/ui/installer-dialog.blp -bottles/frontend/ui/journal-dialog.blp -bottles/frontend/ui/launch-options-dialog.blp -bottles/frontend/ui/proton-alert-dialog.blp -bottles/frontend/ui/rename-program-dialog.blp -bottles/frontend/ui/vmtouch-dialog.blp -bottles/frontend/ui/sandbox-dialog.blp -bottles/frontend/ui/upgrade-versioning-dialog.blp -bottles/frontend/ui/vkbasalt-dialog.blp -bottles/frontend/ui/mangohud-dialog.blp -bottles/frontend/ui/dll-override-entry.blp -bottles/frontend/ui/drive-entry.blp -bottles/frontend/ui/env-var-entry.blp -bottles/frontend/ui/exclusion-pattern-row.blp -bottles/frontend/ui/importer-row.blp -bottles/frontend/ui/importer-view.blp -bottles/frontend/ui/installer-row.blp -bottles/frontend/ui/library-entry.blp -bottles/frontend/ui/library-view.blp -bottles/frontend/ui/bottle-row.blp -bottles/frontend/ui/bottles-list-view.blp -bottles/frontend/ui/loading-view.blp -bottles/frontend/ui/local-resource-row.blp -bottles/frontend/ui/new-bottle-dialog.blp -bottles/frontend/ui/onboard-dialog.blp -bottles/frontend/ui/preferences.blp -bottles/frontend/ui/program-row.blp -bottles/frontend/ui/state-row.blp -bottles/frontend/ui/task-row.blp -bottles/frontend/ui/window.blp -bottles/frontend/ui/fsr-dialog.blp -bottles/frontend/views/bottle_details_page.py -bottles/frontend/views/details_preferences_page.py -bottles/frontend/views/details_versioning_page.py -bottles/frontend/views/bottle_details_view.py -bottles/frontend/views/importer_view.py -bottles/frontend/views/bottles_list_view.py -bottles/frontend/views/loading_view.py -bottles/frontend/views/new_bottle_dialog.py -bottles/frontend/views/preferences.py -bottles/frontend/views/library_view.py -bottles/frontend/widgets/component.py -bottles/frontend/widgets/dependency.py -bottles/frontend/widgets/importer_row.py -bottles/frontend/widgets/installer_row.py -bottles/frontend/widgets/library_entry.py -bottles/frontend/widgets/program_row.py -bottles/frontend/widgets/state_row.py -bottles/frontend/windows/crash_report_dialog.py -bottles/frontend/windows/display_dialog.py -bottles/frontend/windows/dll_overrides_dialog.py -bottles/frontend/windows/drives_dialog.py -bottles/frontend/windows/environment_variables_dialog.py -bottles/frontend/windows/exclusion_patterns_dialog.py -bottles/frontend/windows/generic.py -bottles/frontend/windows/installer_dialog.py -bottles/frontend/windows/launch_options_dialog.py -bottles/frontend/windows/main_window.py -bottles/frontend/windows/vkbasalt_dialog.py -bottles/frontend/windows/fsr_dialog.py -bottles/frontend/windows/mangohud_dialog.py +bottles/frontend/about.blp +bottles/frontend/component-entry-row.blp +bottles/frontend/dependency-entry-row.blp +bottles/frontend/bottle-details-page.blp +bottles/frontend/details-dependencies-view.blp +bottles/frontend/details-installers-view.blp +bottles/frontend/details-preferences-page.blp +bottles/frontend/details-task-manager-view.blp +bottles/frontend/details-versioning-page.blp +bottles/frontend/bottle-details-view.blp +bottles/frontend/bottle-picker-dialog.blp +bottles/frontend/crash-report-dialog.blp +bottles/frontend/dependencies-check-dialog.blp +bottles/frontend/dll-overrides-dialog.blp +bottles/frontend/drives-dialog.blp +bottles/frontend/duplicate-dialog.blp +bottles/frontend/environment-variables-dialog.blp +bottles/frontend/exclusion-patterns-dialog.blp +bottles/frontend/gamescope-dialog.blp +bottles/frontend/installer-dialog.blp +bottles/frontend/journal-dialog.blp +bottles/frontend/launch-options-dialog.blp +bottles/frontend/proton-alert-dialog.blp +bottles/frontend/rename-program-dialog.blp +bottles/frontend/vmtouch-dialog.blp +bottles/frontend/sandbox-dialog.blp +bottles/frontend/upgrade-versioning-dialog.blp +bottles/frontend/vkbasalt-dialog.blp +bottles/frontend/mangohud-dialog.blp +bottles/frontend/dll-override-entry.blp +bottles/frontend/drive-entry.blp +bottles/frontend/env-var-entry.blp +bottles/frontend/exclusion-pattern-row.blp +bottles/frontend/importer-row.blp +bottles/frontend/importer-view.blp +bottles/frontend/installer-row.blp +bottles/frontend/library-entry.blp +bottles/frontend/library-view.blp +bottles/frontend/bottle-row.blp +bottles/frontend/bottles-list-view.blp +bottles/frontend/loading-view.blp +bottles/frontend/local-resource-row.blp +bottles/frontend/new-bottle-dialog.blp +bottles/frontend/onboard-dialog.blp +bottles/frontend/preferences.blp +bottles/frontend/program-row.blp +bottles/frontend/state-row.blp +bottles/frontend/task-row.blp +bottles/frontend/window.blp +bottles/frontend/fsr-dialog.blp +bottles/frontend/bottle_details_page.py +bottles/frontend/details_preferences_page.py +bottles/frontend/details_versioning_page.py +bottles/frontend/bottle_details_view.py +bottles/frontend/importer_view.py +bottles/frontend/bottles_list_view.py +bottles/frontend/loading_view.py +bottles/frontend/new_bottle_dialog.py +bottles/frontend/preferences.py +bottles/frontend/library_view.py +bottles/frontend/component.py +bottles/frontend/dependency.py +bottles/frontend/importer_row.py +bottles/frontend/installer_row.py +bottles/frontend/library_entry.py +bottles/frontend/program_row.py +bottles/frontend/state_row.py +bottles/frontend/crash_report_dialog.py +bottles/frontend/display_dialog.py +bottles/frontend/dll_overrides_dialog.py +bottles/frontend/drives_dialog.py +bottles/frontend/environment_variables_dialog.py +bottles/frontend/exclusion_patterns_dialog.py +bottles/frontend/generic.py +bottles/frontend/installer_dialog.py +bottles/frontend/launch_options_dialog.py +bottles/frontend/main_window.py +bottles/frontend/vkbasalt_dialog.py +bottles/frontend/fsr_dialog.py +bottles/frontend/mangohud_dialog.py data/com.usebottles.bottles.desktop.in.in data/com.usebottles.bottles.gschema.xml data/com.usebottles.bottles.metainfo.xml.in From 24019db5b722473cc297b9ef0a0b04980a085ff6 Mon Sep 17 00:00:00 2001 From: EmoonX Date: Tue, 14 Jan 2025 14:00:56 -0300 Subject: [PATCH 054/146] chore: Add `pyupgrade` as a pre-commit hook --- .pre-commit-config.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 55478f22819..44316bfa1ef 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -13,6 +13,12 @@ repos: args: ["--autofix", "--no-sort-keys", "--indent", "4"] - id: check-added-large-files +- repo: https://github.com/asottile/pyupgrade + rev: v3.19.1 + hooks: + - id: pyupgrade + args: ["--py312-plus"] + - repo: https://github.com/astral-sh/ruff-pre-commit rev: v0.8.2 hooks: From 8e12f6d0de730abff618aecbf9e464ca760a7293 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Thu, 16 Jan 2025 19:20:24 -0500 Subject: [PATCH 055/146] chore: Run `pyupgrade` for the entire codebase Co-authored-by: EmoonX --- bottles/backend/cabextract.py | 3 +-- bottles/backend/downloader.py | 3 +-- bottles/backend/globals.py | 5 ++-- bottles/backend/managers/component.py | 7 +++--- bottles/backend/managers/conf.py | 13 +++++----- bottles/backend/managers/data.py | 2 +- bottles/backend/managers/dependency.py | 4 ++- bottles/backend/managers/epicgamesstore.py | 2 +- bottles/backend/managers/installer.py | 3 +-- bottles/backend/managers/journal.py | 5 ++-- bottles/backend/managers/library.py | 2 +- bottles/backend/managers/manager.py | 22 ++++++++-------- bottles/backend/managers/sandbox.py | 9 +++---- bottles/backend/managers/steam.py | 17 ++++++------- bottles/backend/managers/template.py | 4 +-- bottles/backend/managers/ubisoftconnect.py | 9 +++---- bottles/backend/managers/versioning.py | 18 ++++++------- bottles/backend/models/config.py | 11 ++++---- bottles/backend/models/vdict.py | 18 ++++++------- bottles/backend/state.py | 25 ++++++++++--------- bottles/backend/utils/connection.py | 7 +++--- bottles/backend/utils/file.py | 6 ++--- bottles/backend/utils/generic.py | 3 +-- bottles/backend/utils/json.py | 10 ++++---- bottles/backend/utils/manager.py | 5 ++-- bottles/backend/utils/singleton.py | 2 +- bottles/backend/utils/steam.py | 8 +++--- bottles/backend/utils/threading.py | 2 +- bottles/backend/utils/vdf.py | 10 +++----- bottles/backend/wine/cmd.py | 6 ++--- bottles/backend/wine/executor.py | 25 +++++++++---------- bottles/backend/wine/explorer.py | 10 +++----- bottles/backend/wine/msiexec.py | 18 ++++++------- bottles/backend/wine/net.py | 8 +++--- bottles/backend/wine/notepad.py | 4 +-- bottles/backend/wine/reg.py | 15 +++++------ bottles/backend/wine/register.py | 7 +++--- bottles/backend/wine/start.py | 10 +++----- bottles/backend/wine/uninstaller.py | 6 ++--- bottles/backend/wine/wineboot.py | 2 +- bottles/backend/wine/winecommand.py | 19 +++++++------- bottles/backend/wine/winedbg.py | 5 ++-- bottles/backend/wine/wineprogram.py | 15 ++++++----- bottles/backend/wine/xcopy.py | 3 +-- bottles/frontend/bottle_details_page.py | 5 ++-- bottles/frontend/bottle_details_view.py | 3 +-- bottles/frontend/component_entry_row.py | 3 +-- bottles/frontend/details_dependencies_view.py | 3 +-- bottles/frontend/details_preferences_page.py | 2 +- bottles/frontend/details_task_manager_view.py | 5 ++-- bottles/frontend/gtk.py | 3 +-- bottles/frontend/new_bottle_dialog.py | 4 +-- bottles/frontend/operation.py | 3 +-- bottles/frontend/window.py | 5 ++-- bottles/tests/backend/utils/test_generic.py | 4 +-- 55 files changed, 193 insertions(+), 235 deletions(-) diff --git a/bottles/backend/cabextract.py b/bottles/backend/cabextract.py index 4fcf3702361..bfe6cd00b5a 100644 --- a/bottles/backend/cabextract.py +++ b/bottles/backend/cabextract.py @@ -19,7 +19,6 @@ import shlex import shutil import subprocess -from typing import Optional from bottles.backend.logger import Logger @@ -47,7 +46,7 @@ def run( self, path: str, name: str = "", - files: Optional[list] = None, + files: list | None = None, destination: str = "", ): if files is None: diff --git a/bottles/backend/downloader.py b/bottles/backend/downloader.py index 9772be16389..482e88f0908 100644 --- a/bottles/backend/downloader.py +++ b/bottles/backend/downloader.py @@ -18,7 +18,6 @@ import shutil import sys import time -from typing import Optional import requests @@ -38,7 +37,7 @@ class Downloader: """ def __init__( - self, url: str, file: str, update_func: Optional[TaskStreamUpdateHandler] = None + self, url: str, file: str, update_func: TaskStreamUpdateHandler | None = None ): self.start_time = None self.url = url diff --git a/bottles/backend/globals.py b/bottles/backend/globals.py index 488acea3154..8123b2396ba 100644 --- a/bottles/backend/globals.py +++ b/bottles/backend/globals.py @@ -18,7 +18,6 @@ import os import shutil from pathlib import Path -from typing import Dict from bottles.backend.utils import yaml, json @@ -82,7 +81,7 @@ class TrdyPaths: vmtouch_available = shutil.which("vmtouch") or False base_version = "" if os.path.isfile("/app/manifest.json"): - with open("/app/manifest.json", mode="r", encoding="utf-8") as file: + with open("/app/manifest.json", encoding="utf-8") as file: base_version = ( json.load(file) # type: ignore .get("base-version", "") @@ -90,4 +89,4 @@ class TrdyPaths: ) # encoding detection correction, following windows defaults -locale_encodings: Dict[str, str] = {"ja_JP": "cp932", "zh_CN": "gbk"} +locale_encodings: dict[str, str] = {"ja_JP": "cp932", "zh_CN": "gbk"} diff --git a/bottles/backend/managers/component.py b/bottles/backend/managers/component.py index b9ecacc41cf..9065f7f337f 100644 --- a/bottles/backend/managers/component.py +++ b/bottles/backend/managers/component.py @@ -20,7 +20,6 @@ import shutil import tarfile from functools import lru_cache -from typing import Optional import pycurl @@ -131,7 +130,7 @@ def download( file: str, rename: str = "", checksum: str = "", - func: Optional[TaskStreamUpdateHandler] = None, + func: TaskStreamUpdateHandler | None = None, ) -> bool: """Download a component from the Bottles repository.""" @@ -274,7 +273,7 @@ def extract(name: str, component: str, archive: str) -> bool: root_dir = tar.getnames()[0] tar.extractall(path) tar.close() - except (tarfile.TarError, IOError, EOFError): + except (tarfile.TarError, OSError, EOFError): with contextlib.suppress(FileNotFoundError): os.remove(os.path.join(Paths.temp, archive)) with contextlib.suppress(FileNotFoundError): @@ -301,7 +300,7 @@ def install( self, component_type: str, component_name: str, - func: Optional[TaskStreamUpdateHandler] = None, + func: TaskStreamUpdateHandler | None = None, ): """ This function is used to install a component. It automatically diff --git a/bottles/backend/managers/conf.py b/bottles/backend/managers/conf.py index 736627d4c31..2936700746b 100644 --- a/bottles/backend/managers/conf.py +++ b/bottles/backend/managers/conf.py @@ -1,16 +1,15 @@ import os from configparser import ConfigParser -from typing import Optional from bottles.backend.utils import yaml, json -class ConfigManager(object): +class ConfigManager: def __init__( self, - config_file: Optional[str] = None, + config_file: str | None = None, config_type: str = "ini", - config_string: Optional[str] = None, + config_string: str | None = None, ): self.config_file = config_file self.config_string = config_string @@ -44,10 +43,10 @@ def read(self): # noinspection PyProtectedMember res = config._sections elif self.config_type == "json": - with open(self.config_file, "r") as f: + with open(self.config_file) as f: res = json.load(f) elif self.config_type == "yaml" or self.config_type == "yml": - with open(self.config_file, "r") as f: + with open(self.config_file) as f: res = yaml.load(f) else: raise ValueError("Invalid configuration type") @@ -94,7 +93,7 @@ def write_ini(self): with open(self.config_file, "w") as f: config.write(f) - def write_dict(self, config_file: Optional[str] = None): + def write_dict(self, config_file: str | None = None): if self.config_file is None and config_file is None: raise ValueError("No config path specified") elif self.config_file is None and config_file is not None: diff --git a/bottles/backend/managers/data.py b/bottles/backend/managers/data.py index d5224eb1c02..fc463840ca4 100644 --- a/bottles/backend/managers/data.py +++ b/bottles/backend/managers/data.py @@ -45,7 +45,7 @@ def __init__(self): def __get_data(self): try: - with open(self.__p_data, "r") as s: + with open(self.__p_data) as s: self.__data = yaml.load(s) if self.__data is None: raise AttributeError diff --git a/bottles/backend/managers/dependency.py b/bottles/backend/managers/dependency.py index ce238094b56..0c95dfc8dbf 100644 --- a/bottles/backend/managers/dependency.py +++ b/bottles/backend/managers/dependency.py @@ -91,7 +91,9 @@ def install(self, config: BottleConfig, dependency: list) -> Result: task_id = TaskManager.add(Task(title=dependency[0])) logging.info( - "Installing dependency [%s] in bottle [%s]." % (dependency[0], config.Name), + "Installing dependency [{}] in bottle [{}].".format( + dependency[0], config.Name + ), ) manifest = self.get_dependency(dependency[0]) if not manifest: diff --git a/bottles/backend/managers/epicgamesstore.py b/bottles/backend/managers/epicgamesstore.py index 6fb93379513..127fe616f95 100644 --- a/bottles/backend/managers/epicgamesstore.py +++ b/bottles/backend/managers/epicgamesstore.py @@ -59,7 +59,7 @@ def get_installed_games(config: BottleConfig) -> list: if dat_path is None: return [] - with open(dat_path, "r") as dat: + with open(dat_path) as dat: data = json.load(dat) for game in data["InstallationList"]: diff --git a/bottles/backend/managers/installer.py b/bottles/backend/managers/installer.py index 0fb1e65f278..5bf63a53786 100644 --- a/bottles/backend/managers/installer.py +++ b/bottles/backend/managers/installer.py @@ -18,7 +18,6 @@ import subprocess import uuid from functools import lru_cache -from typing import Optional import markdown import pycurl @@ -358,7 +357,7 @@ def install( installer: dict, step_fn: callable, is_final: bool = True, - local_resources: Optional[dict] = None, + local_resources: dict | None = None, ): manifest = self.get_installer(installer[0]) _config = config diff --git a/bottles/backend/managers/journal.py b/bottles/backend/managers/journal.py index d993f763226..8c471ff180b 100644 --- a/bottles/backend/managers/journal.py +++ b/bottles/backend/managers/journal.py @@ -20,7 +20,6 @@ import shutil import uuid from datetime import datetime, timedelta -from typing import Optional from bottles.backend.globals import Paths from bottles.backend.utils import yaml @@ -52,7 +51,7 @@ def __get_journal() -> dict: with open(JournalManager.path, "w") as f: yaml.dump({}, f) - with open(JournalManager.path, "r") as f: + with open(JournalManager.path) as f: try: journal = yaml.load(f) except yaml.YAMLError: @@ -100,7 +99,7 @@ def __clean_old(): JournalManager.__save_journal(journal) @staticmethod - def __save_journal(journal: Optional[dict] = None): + def __save_journal(journal: dict | None = None): """Save the journal to the journal file.""" if journal is None: journal = JournalManager.__get_journal() diff --git a/bottles/backend/managers/library.py b/bottles/backend/managers/library.py index d2421344b0c..d462c8de511 100644 --- a/bottles/backend/managers/library.py +++ b/bottles/backend/managers/library.py @@ -49,7 +49,7 @@ def load_library(self, silent=False): self.__library = {} self.save_library() else: - with open(self.library_path, "r") as library_file: + with open(self.library_path) as library_file: self.__library = yaml.load(library_file) if self.__library is None: diff --git a/bottles/backend/managers/manager.py b/bottles/backend/managers/manager.py index 8b04c30e218..fb4504d1c6d 100644 --- a/bottles/backend/managers/manager.py +++ b/bottles/backend/managers/manager.py @@ -26,7 +26,7 @@ from datetime import datetime from gettext import gettext as _ from glob import glob -from typing import Any, Dict, List, Optional +from typing import Any import pathvalidate @@ -91,7 +91,7 @@ class Manager(metaclass=Singleton): vkd3d_available = [] nvapi_available = [] latencyflex_available = [] - local_bottles: Dict[str, BottleConfig] = {} + local_bottles: dict[str, BottleConfig] = {} supported_runtimes = {} supported_winebridge = {} supported_wine_runners = {} @@ -413,7 +413,7 @@ def check_runners(self, install_latest: bool = True) -> bool: if len(self.runners_available) > 0: logging.info( - "Runners found:\n - {0}".format("\n - ".join(self.runners_available)) + "Runners found:\n - {}".format("\n - ".join(self.runners_available)) ) tmp_runners = [x for x in self.runners_available if not x.startswith("sys-")] @@ -464,7 +464,7 @@ def check_runtimes(self, install_latest: bool = True) -> bool: manifest = os.path.join(Paths.runtimes, runtime, "manifest.yml") if os.path.exists(manifest): - with open(manifest, "r") as f: + with open(manifest) as f: data = yaml.load(f) version = data.get("version") if version: @@ -493,7 +493,7 @@ def check_winebridge( version_file = os.path.join(Paths.winebridge, "VERSION") if os.path.exists(version_file): - with open(version_file, "r") as f: + with open(version_file) as f: version = f.read().strip() if version: self.winebridge_available = [f"winebridge-{version}"] @@ -630,7 +630,7 @@ def __check_component( if len(component["available"]) > 0: logging.info( - "{0}s found:\n - {1}".format( + "{}s found:\n - {}".format( component_type.capitalize(), "\n - ".join(component["available"]) ) ) @@ -663,7 +663,7 @@ def __check_component( except ValueError: return sorted(component["available"], reverse=True) - def get_programs(self, config: BottleConfig) -> List[dict]: + def get_programs(self, config: BottleConfig) -> list[dict]: """ Get the list of programs (both from the drive and the user defined in the bottle configuration file). @@ -825,7 +825,7 @@ def process_bottle(bottle): _config = os.path.join(_bottle, "bottle.yml") if os.path.exists(_placeholder): - with open(_placeholder, "r") as f: + with open(_placeholder) as f: try: placeholder_yaml = yaml.load(f) if placeholder_yaml.get("Path"): @@ -951,7 +951,7 @@ def process_bottle(bottle): if len(self.local_bottles) > 0 and not silent: logging.info( - "Bottles found:\n - {0}".format("\n - ".join(self.local_bottles)) + "Bottles found:\n - {}".format("\n - ".join(self.local_bottles)) ) if ( @@ -1138,7 +1138,7 @@ def create_bottle( sandbox: bool = False, fn_logger: callable = None, arch: str = "win64", - custom_environment: Optional[str] = None, + custom_environment: str | None = None, ) -> Result[dict]: """ Create a new bottle from the given arguments. @@ -1392,7 +1392,7 @@ def components_check(): env = Samples.environments[environment.lower()] elif custom_environment: try: - with open(custom_environment, "r") as f: + with open(custom_environment) as f: env = yaml.load(f.read()) logging.warning("Using a custom environment recipe…") log_update(_("(!) Using a custom environment recipe…")) diff --git a/bottles/backend/managers/sandbox.py b/bottles/backend/managers/sandbox.py index c943e98995a..2f5661d994e 100644 --- a/bottles/backend/managers/sandbox.py +++ b/bottles/backend/managers/sandbox.py @@ -19,17 +19,16 @@ import os import shlex import subprocess -from typing import Optional class SandboxManager: def __init__( self, - envs: Optional[dict] = None, - chdir: Optional[str] = None, + envs: dict | None = None, + chdir: str | None = None, clear_env: bool = False, - share_paths_ro: Optional[list] = None, - share_paths_rw: Optional[list] = None, + share_paths_ro: list | None = None, + share_paths_rw: list | None = None, share_net: bool = False, share_user: bool = False, share_host_ro: bool = True, diff --git a/bottles/backend/managers/steam.py b/bottles/backend/managers/steam.py index 0596dec51a6..495214ad52d 100644 --- a/bottles/backend/managers/steam.py +++ b/bottles/backend/managers/steam.py @@ -24,7 +24,6 @@ from functools import lru_cache from glob import glob from pathlib import Path -from typing import Dict, Optional from bottles.backend.globals import Paths from bottles.backend.models.config import BottleConfig @@ -51,7 +50,7 @@ class SteamManager: def __init__( self, - config: Optional[BottleConfig] = None, + config: BottleConfig | None = None, is_windows: bool = False, check_only: bool = False, ): @@ -106,7 +105,7 @@ def get_acf_data(libraryfolder: str, app_id: str) -> dict | None: if not os.path.isfile(acf_path): return None - with open(acf_path, "r", errors="replace") as f: + with open(acf_path, errors="replace") as f: data = SteamUtils.parse_acf(f.read()) return data @@ -133,7 +132,7 @@ def __get_library_folders(self) -> list | None: logging.warning("Could not find the libraryfolders.vdf file") return None - with open(library_folders_path, "r", errors="replace") as f: + with open(library_folders_path, errors="replace") as f: _library_folders = SteamUtils.parse_vdf(f.read()) if _library_folders is None or not _library_folders.get("libraryfolders"): @@ -168,7 +167,7 @@ def __get_local_config(self) -> dict: if self.localconfig_path is None: return {} - with open(self.localconfig_path, "r", errors="replace") as f: + with open(self.localconfig_path, errors="replace") as f: data = SteamUtils.parse_vdf(f.read()) if data is None: @@ -192,14 +191,14 @@ def save_local_config(self, new_data: dict): @staticmethod @lru_cache - def get_runner_path(pfx_path: str) -> Optional[str]: + def get_runner_path(pfx_path: str) -> str | None: """Get runner path from config_info file""" config_info = os.path.join(pfx_path, "config_info") if not os.path.isfile(config_info): return None - with open(config_info, "r") as f: + with open(config_info) as f: lines = f.readlines() if len(lines) < 10: logging.error( @@ -273,7 +272,7 @@ def get_installed_apps_as_programs(self) -> list: return apps - def list_prefixes(self) -> Dict[str, BottleConfig]: + def list_prefixes(self) -> dict[str, BottleConfig]: apps = self.list_apps_ids() prefixes = {} @@ -391,7 +390,7 @@ def get_app_config(self, prefix: str) -> dict: return apps[prefix] - def get_launch_options(self, prefix: str, app_conf: Optional[dict] = None) -> {}: + def get_launch_options(self, prefix: str, app_conf: dict | None = None) -> {}: if app_conf is None: app_conf = self.get_app_config(prefix) diff --git a/bottles/backend/managers/template.py b/bottles/backend/managers/template.py index 1ab83ebfbdd..04bb82355fd 100644 --- a/bottles/backend/managers/template.py +++ b/bottles/backend/managers/template.py @@ -104,7 +104,7 @@ def __validate_template(template_uuid: str): logging.error(f"Template {template_uuid} is too small!") result = False - with open(os.path.join(template_path, "template.yml"), "r") as f: + with open(os.path.join(template_path, "template.yml")) as f: template = yaml.load(f) if template["uuid"] != template_uuid: logging.error(f"Template {template_uuid} has invalid uuid!") @@ -114,7 +114,7 @@ def __validate_template(template_uuid: str): @staticmethod def get_template_manifest(template: str): - with open(os.path.join(Paths.templates, template, "template.yml"), "r") as f: + with open(os.path.join(Paths.templates, template, "template.yml")) as f: return yaml.load(f) @staticmethod diff --git a/bottles/backend/managers/ubisoftconnect.py b/bottles/backend/managers/ubisoftconnect.py index 120d2cc9019..e56633e4094 100644 --- a/bottles/backend/managers/ubisoftconnect.py +++ b/bottles/backend/managers/ubisoftconnect.py @@ -17,7 +17,6 @@ import os import uuid -from typing import Optional from bottles.backend.models.config import BottleConfig from bottles.backend.utils.manager import ManagerUtils @@ -56,9 +55,9 @@ def get_installed_games(config: BottleConfig) -> list: """ found = {} games = [] - key: Optional[str] = None - appid: Optional[str] = None - thumb: Optional[str] = None + key: str | None = None + appid: str | None = None + thumb: str | None = None reg_key = ( "register: HKEY_LOCAL_MACHINE\\SOFTWARE\\Ubisoft\\Launcher\\Installs\\" ) @@ -71,7 +70,7 @@ def get_installed_games(config: BottleConfig) -> list: if conf_path is None: return [] - with open(conf_path, "r", encoding="iso-8859-15") as c: + with open(conf_path, encoding="iso-8859-15") as c: for r in c.readlines(): r = r.strip() diff --git a/bottles/backend/managers/versioning.py b/bottles/backend/managers/versioning.py index 30b63bc6abc..6f5163a1519 100644 --- a/bottles/backend/managers/versioning.py +++ b/bottles/backend/managers/versioning.py @@ -155,9 +155,7 @@ def set_state( status=True, message=_("State {0} restored successfully!").format(state_id), ) - task_id = TaskManager.add( - Task(title=_("Restoring state {} …".format(state_id))) - ) + task_id = TaskManager.add(Task(title=_(f"Restoring state {state_id} …"))) try: repo.restore_state(state_id, ignore=patterns) except FVSStateNotFound: @@ -204,25 +202,27 @@ def set_state( # perform file updates for file in remove_files: - os.remove("%s/drive_c/%s" % (bottle_path, file["file"])) + os.remove("{}/drive_c/{}".format(bottle_path, file["file"])) for file in add_files: - source = "%s/states/%s/drive_c/%s" % ( + source = "{}/states/{}/drive_c/{}".format( bottle_path, str(state_id), file["file"], ) - target = "%s/drive_c/%s" % (bottle_path, file["file"]) + target = "{}/drive_c/{}".format(bottle_path, file["file"]) shutil.copy2(source, target) for file in edit_files: for i in search_sources: - source = "%s/states/%s/drive_c/%s" % (bottle_path, str(i), file["file"]) + source = "{}/states/{}/drive_c/{}".format( + bottle_path, str(i), file["file"] + ) if os.path.isfile(source): checksum = FileUtils().get_checksum(source) if file["checksum"] == checksum: break - target = "%s/drive_c/%s" % (bottle_path, file["file"]) + target = "{}/drive_c/{}".format(bottle_path, file["file"]) shutil.copy2(source, target) # update State in bottle config @@ -250,7 +250,7 @@ def get_state_files( files = file.read() if plain else yaml.load(file.read()) file.close() return files - except (OSError, IOError, yaml.YAMLError): + except (OSError, yaml.YAMLError): logging.error("Could not read the state files file.") return {} diff --git a/bottles/backend/models/config.py b/bottles/backend/models/config.py index d42c6db74a3..9136f027ae2 100644 --- a/bottles/backend/models/config.py +++ b/bottles/backend/models/config.py @@ -3,7 +3,8 @@ import os from dataclasses import dataclass, field, replace, asdict, is_dataclass from io import IOBase -from typing import List, Dict, Optional, ItemsView, Container, IO +from typing import Optional, IO +from collections.abc import ItemsView, Container from bottles.backend.models.result import Result from bottles.backend.utils import yaml @@ -135,9 +136,9 @@ class BottleConfig(DictCompatMixIn): Parameters: BottleParams = field(default_factory=BottleParams) Sandbox: BottleSandboxParams = field(default_factory=BottleSandboxParams) Environment_Variables: dict = field(default_factory=dict) - Installed_Dependencies: List[str] = field(default_factory=list) + Installed_Dependencies: list[str] = field(default_factory=list) DLL_Overrides: dict = field(default_factory=dict) - External_Programs: Dict[str, dict] = field(default_factory=dict) + External_Programs: dict[str, dict] = field(default_factory=dict) Uninstallers: dict = field(default_factory=dict) session_arguments: str = "" run_in_terminal: bool = False @@ -272,8 +273,6 @@ def _filter(cls, data: dict, clazz: object = None) -> dict: v = cls._filter(v, field_type) new_data[k] = v else: - logging.warning( - "Skipping unexpected config '%s' in %s" % (k, clazz.__name__) - ) + logging.warning(f"Skipping unexpected config '{k}' in {clazz.__name__}") return new_data diff --git a/bottles/backend/models/vdict.py b/bottles/backend/models/vdict.py index cc795c074b3..9ee4608e16d 100644 --- a/bottles/backend/models/vdict.py +++ b/bottles/backend/models/vdict.py @@ -102,15 +102,15 @@ def __setitem__(self, key, value): raise KeyError("%s doesn't exist" % repr(key)) else: raise TypeError("Expected either a str or tuple for key") - super(VDFDict, self).__setitem__(key, value) + super().__setitem__(key, value) self.__kcount[key[1]] += 1 def __getitem__(self, key): - return super(VDFDict, self).__getitem__(self._normalize_key(key)) + return super().__getitem__(self._normalize_key(key)) def __delitem__(self, key): key = self._normalize_key(key) - result = super(VDFDict, self).__delitem__(key) + result = super().__delitem__(key) start_idx = self.__omap.index(key) del self.__omap[start_idx] @@ -124,8 +124,8 @@ def __delitem__(self, key): if self.__omap[idx][1] == skey: oldkey = self.__omap[idx] newkey = (dup_idx, skey) - super(VDFDict, self).__setitem__(newkey, self[oldkey]) - super(VDFDict, self).__delitem__(oldkey) + super().__setitem__(newkey, self[oldkey]) + super().__delitem__(oldkey) self.__omap[idx] = newkey dup_idx += 1 @@ -142,7 +142,7 @@ def __iter__(self): return iter(self.iterkeys()) def __contains__(self, key): - return super(VDFDict, self).__contains__(self._normalize_key(key)) + return super().__contains__(self._normalize_key(key)) def __eq__(self, other): if isinstance(other, VDFDict): @@ -154,12 +154,12 @@ def __ne__(self, other): return not self.__eq__(other) def clear(self): - super(VDFDict, self).clear() + super().clear() self.__kcount.clear() self.__omap = list() def get(self, key, *_args): - return super(VDFDict, self).get(self._normalize_key(key), *_args) + return super().get(self._normalize_key(key), *_args) def setdefault(self, key, default=None): if key not in self: @@ -217,7 +217,7 @@ def remove_all_for(self, key): raise TypeError("Key need to be a string.") for idx in _range(self.__kcount[key]): - super(VDFDict, self).__delitem__((idx, key)) + super().__delitem__((idx, key)) self.__omap = list(filter(lambda x: x[1] != key, self.__omap)) diff --git a/bottles/backend/state.py b/bottles/backend/state.py index 38a6ddb225c..e29bbe18862 100644 --- a/bottles/backend/state.py +++ b/bottles/backend/state.py @@ -2,7 +2,8 @@ from enum import Enum from gettext import gettext as _ from threading import Lock as PyLock, Event as PyEvent -from typing import Dict, Callable, Optional, Protocol, List +from typing import Protocol +from collections.abc import Callable from uuid import UUID, uuid4 from bottles.backend.logger import Logger @@ -59,12 +60,12 @@ def __call__( self, received_size: int = 0, total_size: int = 0, - status: Optional[Status] = None, + status: Status | None = None, ) -> None: ... class SignalHandler(Protocol): - def __call__(self, data: Optional[Result] = None) -> None: ... + def __call__(self, data: Result | None = None) -> None: ... @dataclasses.dataclass @@ -76,7 +77,7 @@ class Notification: @dataclasses.dataclass(init=False) class Task: - _task_id: Optional[UUID] = None # should only be set by TaskManager + _task_id: UUID | None = None # should only be set by TaskManager title: str = "Task" _subtitle: str = "" hidden: bool = False # hide from UI @@ -95,7 +96,7 @@ def __init__( self.cancellable = cancellable @property - def task_id(self) -> Optional[UUID]: + def task_id(self) -> UUID | None: return self._task_id @task_id.setter @@ -119,7 +120,7 @@ def stream_update( self, received_size: int = 0, total_size: int = 0, - status: Optional[Status] = None, + status: Status | None = None, ): """This is a default subtitle updating handler for streaming downloading progress""" match status: @@ -138,7 +139,7 @@ def stream_update( class LockManager: - _LOCKS: Dict[Locks, PyLock] = {} + _LOCKS: dict[Locks, PyLock] = {} @classmethod def lock(cls, name: Locks): @@ -168,7 +169,7 @@ class EventManager: Wait for an event that has already been set, will immediately return. """ - _EVENTS: Dict[Events, PyEvent] = {} + _EVENTS: dict[Events, PyEvent] = {} @classmethod def wait(cls, event: Events): @@ -194,10 +195,10 @@ def reset(cls, event: Events): class TaskManager: """Long-running tasks are registered here, for tracking and display them on UI""" - _TASKS: Dict[UUID, Task] = {} # {UUID4: Task} + _TASKS: dict[UUID, Task] = {} # {UUID4: Task} @classmethod - def get(cls, task_id: UUID) -> Optional[Task]: + def get(cls, task_id: UUID) -> Task | None: return cls._TASKS.get(task_id) @classmethod @@ -220,7 +221,7 @@ def remove(cls, task: UUID | Task): class SignalManager: """sync backend state to frontend via registered signal handlers""" - _SIGNALS: Dict[Signals, List[SignalHandler]] = {} + _SIGNALS: dict[Signals, list[SignalHandler]] = {} @classmethod def connect(cls, signal: Signals, handler: SignalHandler) -> None: @@ -228,7 +229,7 @@ def connect(cls, signal: Signals, handler: SignalHandler) -> None: cls._SIGNALS[signal].append(handler) @classmethod - def send(cls, signal: Signals, data: Optional[Result] = None) -> None: + def send(cls, signal: Signals, data: Result | None = None) -> None: """ Send signal should only be called by backend logic diff --git a/bottles/backend/utils/connection.py b/bottles/backend/utils/connection.py index 46d905adcbc..acc84a33636 100644 --- a/bottles/backend/utils/connection.py +++ b/bottles/backend/utils/connection.py @@ -18,7 +18,6 @@ import os from datetime import datetime from gettext import gettext as _ -from typing import Optional import pycurl @@ -36,7 +35,7 @@ class ConnectionUtils: notified and False will be returned, otherwise True. """ - _status: Optional[bool] = None + _status: bool | None = None last_check = None def __init__(self, force_offline=False, **kwargs): @@ -47,7 +46,7 @@ def __init__(self, force_offline=False, **kwargs): SignalManager.connect(Signals.ForceStopNetworking, self.stop_check) @property - def status(self) -> Optional[bool]: + def status(self) -> bool | None: return self._status @status.setter @@ -69,7 +68,7 @@ def stop_check(self, res: Result): if res.status: self.do_check_connection = False - def check_connection(self, show_notification=False) -> Optional[bool]: + def check_connection(self, show_notification=False) -> bool | None: """check network status, send result through signal NetworkReady and return""" if self.force_offline or "FORCE_OFFLINE" in os.environ: logging.info("Forcing offline mode") diff --git a/bottles/backend/utils/file.py b/bottles/backend/utils/file.py index f07dbbea00c..31f99d45329 100644 --- a/bottles/backend/utils/file.py +++ b/bottles/backend/utils/file.py @@ -49,7 +49,7 @@ def get_checksum(file): def use_insensitive_ext(string): """Converts a glob pattern into a case-insensitive glob pattern""" ext = string.split(".")[1] - globlist = ["[%s%s]" % (c.lower(), c.upper()) for c in ext] + globlist = [f"[{c.lower()}{c.upper()}]" for c in ext] return "*.%s" % "".join(globlist) @staticmethod @@ -66,10 +66,10 @@ def get_human_size_legacy(size: float) -> str: """Returns a human readable size from a given float size""" for unit in ["", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi"]: if abs(size) < 1024.0: - return "%3.1f%s%s" % (size, unit, "B") + return "{:3.1f}{}{}".format(size, unit, "B") size /= 1024.0 - return "%.1f%s%s" % (size, "Yi", "B") + return "{:.1f}{}{}".format(size, "Yi", "B") def get_path_size(self, path: str, human: bool = True) -> str | float: """ diff --git a/bottles/backend/utils/generic.py b/bottles/backend/utils/generic.py index a6b607cbd05..6f44fd7cf3f 100644 --- a/bottles/backend/utils/generic.py +++ b/bottles/backend/utils/generic.py @@ -20,7 +20,6 @@ import re import string import subprocess -from typing import Optional import chardet @@ -42,7 +41,7 @@ def validate_url(url: str): return re.match(regex, url) is not None -def detect_encoding(text: bytes, locale_hint: str = None) -> Optional[str]: +def detect_encoding(text: bytes, locale_hint: str = None) -> str | None: """ Detect the encoding of a text by its bytes. Return None if it can't be detected. diff --git a/bottles/backend/utils/json.py b/bottles/backend/utils/json.py index a99b2ba32be..1e1e47006c0 100644 --- a/bottles/backend/utils/json.py +++ b/bottles/backend/utils/json.py @@ -2,7 +2,7 @@ import json import json as _json -from typing import Optional, IO, Any, Type +from typing import IO, Any from bottles.backend.models.config import DictCompatMixIn @@ -30,8 +30,8 @@ def dump( obj: Any, fp: IO[str], *, - indent: Optional[str | int] = None, - cls: Optional[Type[_json.JSONEncoder]] = None, + indent: str | int | None = None, + cls: type[_json.JSONEncoder] | None = None, ) -> None: """ Serialize obj as a JSON formatted stream to fp (a .write()-supporting file-like object). @@ -49,8 +49,8 @@ def dump( def dumps( obj: Any, *, - indent: Optional[str | int] = None, - cls: Optional[Type[_json.JSONEncoder]] = None, + indent: str | int | None = None, + cls: type[_json.JSONEncoder] | None = None, ) -> str: """ Serialize obj to a JSON formatted str. diff --git a/bottles/backend/utils/manager.py b/bottles/backend/utils/manager.py index bd5ecc58752..1a7e29d0ed8 100644 --- a/bottles/backend/utils/manager.py +++ b/bottles/backend/utils/manager.py @@ -20,7 +20,6 @@ from datetime import datetime from gettext import gettext as _ from glob import glob -from typing import Optional import icoextract # type: ignore [import-untyped] @@ -43,7 +42,7 @@ class ManagerUtils: @staticmethod def open_filemanager( - config: Optional[BottleConfig] = None, + config: BottleConfig | None = None, path_type: str = "bottle", component: str = "", custom_path: str = "", @@ -152,7 +151,7 @@ def move_file_to_bottle( fn_update(_size) fn_update(1) return file_new_path - except (OSError, IOError): + except OSError: logging.error(f"Could not copy file {file_path} to the bottle.") return False diff --git a/bottles/backend/utils/singleton.py b/bottles/backend/utils/singleton.py index 3776cb92d12..9767a5c7e1a 100644 --- a/bottles/backend/utils/singleton.py +++ b/bottles/backend/utils/singleton.py @@ -3,5 +3,5 @@ class Singleton(type): def __call__(cls, *args, **kwargs): if cls not in cls._instances: - cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs) + cls._instances[cls] = super().__call__(*args, **kwargs) return cls._instances[cls] diff --git a/bottles/backend/utils/steam.py b/bottles/backend/utils/steam.py index 8e867acef60..d420d2c2125 100644 --- a/bottles/backend/utils/steam.py +++ b/bottles/backend/utils/steam.py @@ -17,7 +17,7 @@ import os import shlex -from typing import TextIO, Optional +from typing import TextIO from bottles.backend.logger import Logger from bottles.backend.models.vdict import VDFDict @@ -57,7 +57,7 @@ def is_proton(path: str) -> bool: if not os.path.isfile(toolmanifest): return False - f = open(toolmanifest, "r", errors="replace") + f = open(toolmanifest, errors="replace") data = SteamUtils.parse_vdf(f.read()) compat_layer_name = data.get("manifest", {}).get("compatmanager_layer_name", {}) @@ -66,7 +66,7 @@ def is_proton(path: str) -> bool: return "proton" in compat_layer_name or "proton" in commandline @staticmethod - def get_associated_runtime(path: str) -> Optional[str]: + def get_associated_runtime(path: str) -> str | None: """ Get the associated runtime of a Proton directory. """ @@ -76,7 +76,7 @@ def get_associated_runtime(path: str) -> Optional[str]: return None runtime = "scout" - f = open(toolmanifest, "r", errors="replace") + f = open(toolmanifest, errors="replace") data = SteamUtils.parse_vdf(f.read()) tool_appid = data.get("manifest", {}).get("require_tool_appid", {}) diff --git a/bottles/backend/utils/threading.py b/bottles/backend/utils/threading.py index 57beb6d1ec0..911dc0fb3a1 100644 --- a/bottles/backend/utils/threading.py +++ b/bottles/backend/utils/threading.py @@ -45,7 +45,7 @@ def __init__( f"(from main thread: {threading.current_thread() is threading.main_thread()})." ) - super(RunAsync, self).__init__(target=self.__target, args=args, kwargs=kwargs) + super().__init__(target=self.__target, args=args, kwargs=kwargs) self.task_func = task_func diff --git a/bottles/backend/utils/vdf.py b/bottles/backend/utils/vdf.py index 96c932b9ce1..14277c73eba 100644 --- a/bottles/backend/utils/vdf.py +++ b/bottles/backend/utils/vdf.py @@ -294,15 +294,14 @@ def _dump_gen(data, pretty=False, escaped=True, level=0): key = _escape(key) if isinstance(value, Mapping): - yield '%s"%s"\n%s{\n' % (line_indent, key, line_indent) - for chunk in _dump_gen(value, pretty, escaped, level + 1): - yield chunk + yield f'{line_indent}"{key}"\n{line_indent}{{\n' + yield from _dump_gen(value, pretty, escaped, level + 1) yield "%s}\n" % line_indent else: if escaped and isinstance(value, string_type): value = _escape(value) - yield '%s"%s" "%s"\n' % (line_indent, key, value) + yield f'{line_indent}"{key}" "{value}"\n' # binary VDF @@ -520,8 +519,7 @@ def _binary_dump_gen(obj, level=0, alt_format=False): if isinstance(value, Mapping): yield BIN_NONE + key + BIN_NONE - for chunk in _binary_dump_gen(value, level + 1, alt_format=alt_format): - yield chunk + yield from _binary_dump_gen(value, level + 1, alt_format=alt_format) elif isinstance(value, UINT_64): yield BIN_UINT64 + key + BIN_NONE + uint64.pack(value) elif isinstance(value, INT_64): diff --git a/bottles/backend/wine/cmd.py b/bottles/backend/wine/cmd.py index 2b1e9852d85..268e152a454 100644 --- a/bottles/backend/wine/cmd.py +++ b/bottles/backend/wine/cmd.py @@ -1,5 +1,3 @@ -from typing import Optional - from bottles.backend.logger import Logger from bottles.backend.wine.wineprogram import WineProgram @@ -15,8 +13,8 @@ def run_batch( batch: str, terminal: bool = True, args: str = "", - environment: Optional[dict] = None, - cwd: Optional[str] = None, + environment: dict | None = None, + cwd: str | None = None, ): args = f"/c {batch} {args}" diff --git a/bottles/backend/wine/executor.py b/bottles/backend/wine/executor.py index 7c4646e551c..368fee77aad 100644 --- a/bottles/backend/wine/executor.py +++ b/bottles/backend/wine/executor.py @@ -1,7 +1,6 @@ import os import shlex import uuid -from typing import Optional from bottles.backend.dlls.dxvk import DXVKComponent from bottles.backend.dlls.nvapi import NVAPIComponent @@ -28,19 +27,19 @@ def __init__( exec_path: str, args: str = "", terminal: bool = False, - environment: Optional[dict] = None, + environment: dict | None = None, move_file: bool = False, move_upd_fn: callable = None, - pre_script: Optional[str] = None, - post_script: Optional[str] = None, - cwd: Optional[str] = None, - monitoring: Optional[list] = None, - program_dxvk: Optional[bool] = None, - program_vkd3d: Optional[bool] = None, - program_nvapi: Optional[bool] = None, - program_fsr: Optional[bool] = None, - program_gamescope: Optional[bool] = None, - program_virt_desktop: Optional[bool] = None, + pre_script: str | None = None, + post_script: str | None = None, + cwd: str | None = None, + monitoring: list | None = None, + program_dxvk: bool | None = None, + program_vkd3d: bool | None = None, + program_nvapi: bool | None = None, + program_fsr: bool | None = None, + program_gamescope: bool | None = None, + program_virt_desktop: bool | None = None, ): logging.info("Launching an executable…") self.config = config @@ -345,7 +344,7 @@ def __set_monitors(self): if not self.monitoring: return - logging.info("Starting {} monitors".format(len(self.monitoring))) + logging.info(f"Starting {len(self.monitoring)} monitors") winedbg = WineDbg(self.config, silent=True) for m in self.monitoring: diff --git a/bottles/backend/wine/explorer.py b/bottles/backend/wine/explorer.py index 34212b92730..d6588cda075 100644 --- a/bottles/backend/wine/explorer.py +++ b/bottles/backend/wine/explorer.py @@ -1,5 +1,3 @@ -from typing import Optional - from bottles.backend.logger import Logger from bottles.backend.wine.wineprogram import WineProgram @@ -15,10 +13,10 @@ def launch_desktop( desktop: str = "shell", width: int = 0, height: int = 0, - program: Optional[str] = None, - args: Optional[str] = None, - environment: Optional[dict] = None, - cwd: Optional[str] = None, + program: str | None = None, + args: str | None = None, + environment: dict | None = None, + cwd: str | None = None, ): _args = f"/desktop={desktop}" diff --git a/bottles/backend/wine/msiexec.py b/bottles/backend/wine/msiexec.py index 3edfa8d0c1e..340d4f5aabb 100644 --- a/bottles/backend/wine/msiexec.py +++ b/bottles/backend/wine/msiexec.py @@ -1,5 +1,3 @@ -from typing import Optional - from bottles.backend.logger import Logger from bottles.backend.wine.wineprogram import WineProgram @@ -15,8 +13,8 @@ def install( pkg_path: str, # or product code args: str = "", terminal: bool = False, - cwd: Optional[str] = None, - environment: Optional[dict] = None, + cwd: str | None = None, + environment: dict | None = None, ): args = f"/i {pkg_path} {args}" @@ -43,7 +41,7 @@ def repair( all_computer_registry_keys: bool = False, all_shortcuts: bool = False, recache: bool = False, - cwd: Optional[str] = None, + cwd: str | None = None, ): """ NOTICE: I have not been able to use the repair in any way, it seems to show @@ -78,13 +76,13 @@ def repair( args=args, communicate=True, minimal=True, cwd=cwd, action_name="repair" ) - def uninstall(self, pkg_path: str, cwd: Optional[str] = None): + def uninstall(self, pkg_path: str, cwd: str | None = None): args = f"/x {pkg_path}" self.launch( args=args, communicate=True, minimal=True, cwd=cwd, action_name="uninstall" ) - def apply_patch(self, patch: str, update: bool = False, cwd: Optional[str] = None): + def apply_patch(self, patch: str, update: bool = False, cwd: str | None = None): args = f"/p {patch}" if update: args = f" /update {patch}" @@ -94,7 +92,7 @@ def apply_patch(self, patch: str, update: bool = False, cwd: Optional[str] = Non ) def uninstall_patch( - self, patch: str, product: Optional[str] = None, cwd: Optional[str] = None + self, patch: str, product: str | None = None, cwd: str | None = None ): args = f"/uninstall {patch}" if product: @@ -108,7 +106,7 @@ def uninstall_patch( action_name="uninstall_patch", ) - def register_module(self, module: str, cwd: Optional[str] = None): + def register_module(self, module: str, cwd: str | None = None): args = f"/y {module}" self.launch( args=args, @@ -118,7 +116,7 @@ def register_module(self, module: str, cwd: Optional[str] = None): action_name="register_module", ) - def unregister_module(self, module: str, cwd: Optional[str] = None): + def unregister_module(self, module: str, cwd: str | None = None): args = f"/z {module}" self.launch( args=args, diff --git a/bottles/backend/wine/net.py b/bottles/backend/wine/net.py index 62657879765..41da0793b2f 100644 --- a/bottles/backend/wine/net.py +++ b/bottles/backend/wine/net.py @@ -1,5 +1,3 @@ -from typing import Optional - from bottles.backend.logger import Logger from bottles.backend.wine.wineprogram import WineProgram @@ -10,7 +8,7 @@ class Net(WineProgram): program = "Wine Services manager" command = "net" - def start(self, name: Optional[str] = None): + def start(self, name: str | None = None): args = "start" if name is not None: @@ -18,7 +16,7 @@ def start(self, name: Optional[str] = None): return self.launch(args=args, communicate=True, action_name="start") - def stop(self, name: Optional[str] = None): + def stop(self, name: str | None = None): args = "stop" if name is not None: @@ -26,7 +24,7 @@ def stop(self, name: Optional[str] = None): return self.launch(args=args, communicate=True, action_name="stop") - def use(self, name: Optional[str] = None): + def use(self, name: str | None = None): # this command has no documentation, not tested yet args = "use" diff --git a/bottles/backend/wine/notepad.py b/bottles/backend/wine/notepad.py index e70b6406442..c2e361d7148 100644 --- a/bottles/backend/wine/notepad.py +++ b/bottles/backend/wine/notepad.py @@ -1,5 +1,3 @@ -from typing import Optional - from bottles.backend.logger import Logger from bottles.backend.wine.wineprogram import WineProgram @@ -18,7 +16,7 @@ def open(self, path: str, as_ansi: bool = False, as_utf16: bool = False): args = f"/w {path}" return self.launch(args=args, communicate=True, action_name="open") - def print(self, path: str, printer_name: Optional[str] = None): + def print(self, path: str, printer_name: str | None = None): args = f"/p {path}" if printer_name: args = f"/pt {path} {printer_name}" diff --git a/bottles/backend/wine/reg.py b/bottles/backend/wine/reg.py index f7737edb679..83c78a1e162 100644 --- a/bottles/backend/wine/reg.py +++ b/bottles/backend/wine/reg.py @@ -4,7 +4,6 @@ import uuid from datetime import datetime from itertools import groupby -from typing import List, Dict, Optional from bottles.backend.globals import Paths from bottles.backend.logger import Logger @@ -28,13 +27,13 @@ class Reg(WineProgram): program = "Wine Registry CLI" command = "reg" - def bulk_add(self, regs: List[RegItem]): + def bulk_add(self, regs: list[RegItem]): """Import multiple registries at once, with v5.00 reg file""" config = self.config logging.info(f"Importing {len(regs)} Key(s) to {config.Name} registry") winedbg = WineDbg(config) - mapping: Dict[str, List[RegItem]] = { + mapping: dict[str, list[RegItem]] = { k: list(v) for k, v in groupby(regs, lambda x: x.key) } reg_file_header = "Windows Registry Editor Version 5.00\n\n" @@ -74,17 +73,19 @@ def bulk_add(self, regs: List[RegItem]): ) logging.info(res.data) - def add(self, key: str, value: str, data: str, value_type: Optional[str] = None): + def add(self, key: str, value: str, data: str, value_type: str | None = None): config = self.config logging.info( f"Adding Key: [{key}] with Value: [{value}] and " f"Data: [{data}] in {config.Name} registry" ) winedbg = WineDbg(config) - args = "add '%s' /v '%s' /d '%s' /f" % (key, value, data) + args = f"add '{key}' /v '{value}' /d '{data}' /f" if value_type is not None: - args = "add '%s' /v '%s' /t %s /d '%s' /f" % (key, value, value_type, data) + args = "add '{}' /v '{}' /t {} /d '{}' /f".format( + key, value, value_type, data + ) # avoid conflicts when executing async winedbg.wait_for_process("reg.exe") @@ -99,7 +100,7 @@ def remove(self, key: str, value: str): f"Removing Value: [{key}] from Key: [{value}] in " f"{config.Name} registry" ) winedbg = WineDbg(config) - args = "delete '%s' /v %s /f" % (key, value) + args = f"delete '{key}' /v {value} /f" # avoid conflicts when executing async winedbg.wait_for_process("reg.exe") diff --git a/bottles/backend/wine/register.py b/bottles/backend/wine/register.py index 5d78237702b..4e850e4eb87 100644 --- a/bottles/backend/wine/register.py +++ b/bottles/backend/wine/register.py @@ -17,7 +17,6 @@ import os import uuid -from typing import Optional from bottles.backend.utils import json @@ -40,7 +39,7 @@ def new(self, path: str): def __get_header(self): """Return the header of the registry file.""" - with open(self.path, "r") as reg: + with open(self.path) as reg: header = reg.readlines(2) return header @@ -101,7 +100,7 @@ def __parse_dict(path: str): return _dict - def compare(self, path: Optional[str] = None, register: object = None): + def compare(self, path: str | None = None, register: object = None): """Compare the current register with the given path or register.""" if path is not None: register = WinRegister().new(path) @@ -133,7 +132,7 @@ def __get_diff(self, register: "WinRegister"): return diff - def update(self, diff: Optional[dict] = None): + def update(self, diff: dict | None = None): """Update the current register with the given diff.""" if diff is None: diff = self.diff # use last diff diff --git a/bottles/backend/wine/start.py b/bottles/backend/wine/start.py index b88738ec11c..7cde9e5ce6b 100644 --- a/bottles/backend/wine/start.py +++ b/bottles/backend/wine/start.py @@ -1,5 +1,3 @@ -from typing import Optional - from bottles.backend.logger import Logger from bottles.backend.wine.wineprogram import WineProgram from bottles.backend.wine.winepath import WinePath @@ -16,10 +14,10 @@ def run( file: str, terminal: bool = True, args: str = "", - environment: Optional[dict] = None, - pre_script: Optional[str] = None, - post_script: Optional[str] = None, - cwd: Optional[str] = None, + environment: dict | None = None, + pre_script: str | None = None, + post_script: str | None = None, + cwd: str | None = None, ): winepath = WinePath(self.config) diff --git a/bottles/backend/wine/uninstaller.py b/bottles/backend/wine/uninstaller.py index 5821251afb7..511db791bdc 100644 --- a/bottles/backend/wine/uninstaller.py +++ b/bottles/backend/wine/uninstaller.py @@ -1,5 +1,3 @@ -from typing import Optional - from bottles.backend.logger import Logger from bottles.backend.wine.wineprogram import WineProgram @@ -10,7 +8,7 @@ class Uninstaller(WineProgram): program = "Wine Uninstaller" command = "uninstaller" - def get_uuid(self, name: Optional[str] = None): + def get_uuid(self, name: str | None = None): args = " --list" if name is not None: @@ -18,7 +16,7 @@ def get_uuid(self, name: Optional[str] = None): return self.launch(args=args, communicate=True, action_name="get_uuid") - def from_uuid(self, uuid: Optional[str] = None): + def from_uuid(self, uuid: str | None = None): args = "" if uuid not in [None, ""]: diff --git a/bottles/backend/wine/wineboot.py b/bottles/backend/wine/wineboot.py index 715e5393a69..b489f321f79 100644 --- a/bottles/backend/wine/wineboot.py +++ b/bottles/backend/wine/wineboot.py @@ -67,7 +67,7 @@ def nv_stop_all_processes(self): for pid in os.listdir("/proc"): if pid.isdigit(): try: - with open(f"/proc/{pid}/environ", "r") as env_file: + with open(f"/proc/{pid}/environ") as env_file: env_vars = env_file.read() if f"BOTTLE={self.config.Path}" in env_vars: os.kill(int(pid), signal.SIGTERM) diff --git a/bottles/backend/wine/winecommand.py b/bottles/backend/wine/winecommand.py index 643335b9df6..5b62a7b64d9 100644 --- a/bottles/backend/wine/winecommand.py +++ b/bottles/backend/wine/winecommand.py @@ -4,7 +4,6 @@ import subprocess import tempfile import shlex -from typing import Optional from bottles.backend.globals import ( Paths, @@ -97,9 +96,9 @@ def __init__( communicate: bool = False, colors: str = "default", minimal: bool = False, # avoid gamemode/gamescope usage - pre_script: Optional[str] = None, - post_script: Optional[str] = None, - cwd: Optional[str] = None, + pre_script: str | None = None, + post_script: str | None = None, + cwd: str | None = None, ): _environment = environment.copy() self.config = self._get_config(config) @@ -156,7 +155,7 @@ def _get_cwd(self, cwd) -> str: def get_env( self, - environment: Optional[dict] = None, + environment: dict | None = None, return_steam_env: bool = False, return_clean_env: bool = False, ) -> dict: @@ -487,11 +486,11 @@ def _get_runner_info(self) -> tuple[str, str]: def get_cmd( self, command, - pre_script: Optional[str] = None, - post_script: Optional[str] = None, + pre_script: str | None = None, + post_script: str | None = None, return_steam_cmd: bool = False, return_clean_cmd: bool = False, - environment: Optional[dict] = None, + environment: dict | None = None, ) -> str: config = self.config params = config.Parameters @@ -536,7 +535,7 @@ def get_cmd( ) logging.info(f"Running Gamescope command: '{command}'") logging.info(f"{gamescope_run} contains:") - with open(gamescope_run, "r") as f: + with open(gamescope_run) as f: logging.info(f"\n\n{f.read()}") # Set file as executable @@ -686,7 +685,7 @@ def _get_sandbox_manager(self) -> SandboxManager: share_sound=self.config.Sandbox.share_sound, ) - def run(self) -> Result[Optional[str]]: + def run(self) -> Result[str | None]: """ Run command with pre-configured parameters diff --git a/bottles/backend/wine/winedbg.py b/bottles/backend/wine/winedbg.py index 4d4096ca84d..738d1137c33 100644 --- a/bottles/backend/wine/winedbg.py +++ b/bottles/backend/wine/winedbg.py @@ -1,7 +1,6 @@ import re import time import subprocess -from typing import Optional from bottles.backend.logger import Logger from bottles.backend.wine.wineprogram import WineProgram @@ -80,7 +79,7 @@ def wait_for_process(self, name: str, timeout: float = 0.5): time.sleep(timeout) return True - def kill_process(self, pid: Optional[str] = None, name: Optional[str] = None): + def kill_process(self, pid: str | None = None, name: str | None = None): """ Kill a process by its PID or name. """ @@ -109,7 +108,7 @@ def kill_process(self, pid: Optional[str] = None, name: Optional[str] = None): if p["name"] == name: self.kill_process(p["pid"], name) - def is_process_alive(self, pid: Optional[str] = None, name: Optional[str] = None): + def is_process_alive(self, pid: str | None = None, name: str | None = None): """ Check if a process is running on the wineprefix. """ diff --git a/bottles/backend/wine/wineprogram.py b/bottles/backend/wine/wineprogram.py index df111ab3130..5bcef08b58f 100644 --- a/bottles/backend/wine/wineprogram.py +++ b/bottles/backend/wine/wineprogram.py @@ -1,5 +1,4 @@ import os -from typing import Optional from bottles.backend.logger import Logger from bottles.backend.globals import Paths @@ -25,7 +24,7 @@ def __init__(self, config: BottleConfig, silent=False): self.config = config self.silent = silent - def get_command(self, args: Optional[str] = None): + def get_command(self, args: str | None = None): command = self.command if self.is_internal: @@ -42,10 +41,10 @@ def launch( terminal: bool = False, minimal: bool = True, communicate: bool = False, - environment: Optional[dict] = None, - pre_script: Optional[str] = None, - post_script: Optional[str] = None, - cwd: Optional[str] = None, + environment: dict | None = None, + pre_script: str | None = None, + post_script: str | None = None, + cwd: str | None = None, action_name: str = "launch", ): if environment is None: @@ -80,8 +79,8 @@ def launch( res = res.run() return res - def launch_terminal(self, args: Optional[str] = None): + def launch_terminal(self, args: str | None = None): self.launch(args=args, terminal=True, action_name="launch_terminal") - def launch_minimal(self, args: Optional[str] = None): + def launch_minimal(self, args: str | None = None): self.launch(args=args, minimal=True, action_name="launch_minimal") diff --git a/bottles/backend/wine/xcopy.py b/bottles/backend/wine/xcopy.py index 104852ae743..ba8e8c97daa 100644 --- a/bottles/backend/wine/xcopy.py +++ b/bottles/backend/wine/xcopy.py @@ -1,4 +1,3 @@ -from typing import Optional from datetime import datetime from bottles.backend.logger import Logger @@ -29,7 +28,7 @@ def copy( include_hidden_and_sys_files: bool = False, continue_if_error: bool = False, copy_attributes: bool = False, - after_date: Optional[datetime] = None, + after_date: datetime | None = None, ): args = f"{source} {dest} /i" diff --git a/bottles/frontend/bottle_details_page.py b/bottles/frontend/bottle_details_page.py index fb01c96b773..57e44ee046a 100644 --- a/bottles/frontend/bottle_details_page.py +++ b/bottles/frontend/bottle_details_page.py @@ -18,7 +18,6 @@ import uuid from datetime import datetime from gettext import gettext as _ -from typing import List, Optional from gi.repository import Gtk, Gio, Adw, Gdk, GLib, Xdp @@ -164,7 +163,7 @@ def __change_page(self, _widget, page_name): def on_drop(self, drop_target, value: Gdk.FileList, x, y, user_data=None): self.drop_overlay.set_visible(False) - files: List[Gio.File] = value.get_files() + files: list[Gio.File] = value.get_files() args = "" file = files[0] if ( @@ -286,7 +285,7 @@ def set_path(_dialog, response): dialog.show() def update_programs( - self, config: Optional[BottleConfig] = None, force_add: dict = None + self, config: BottleConfig | None = None, force_add: dict = None ): """ This function update the programs lists. diff --git a/bottles/frontend/bottle_details_view.py b/bottles/frontend/bottle_details_view.py index f1292ca3025..afe50ab1f82 100644 --- a/bottles/frontend/bottle_details_view.py +++ b/bottles/frontend/bottle_details_view.py @@ -17,7 +17,6 @@ from gettext import gettext as _ -from typing import Optional from gi.repository import Gtk, Adw, GLib @@ -62,7 +61,7 @@ class BottleDetailsView(Adw.Bin): # endregion - def __init__(self, window, config: Optional[BottleConfig] = None, **kwargs): + def __init__(self, window, config: BottleConfig | None = None, **kwargs): super().__init__(**kwargs) # common variables and references diff --git a/bottles/frontend/component_entry_row.py b/bottles/frontend/component_entry_row.py index 4175fa8c36c..f8ae055f2e8 100644 --- a/bottles/frontend/component_entry_row.py +++ b/bottles/frontend/component_entry_row.py @@ -16,7 +16,6 @@ # from gettext import gettext as _ -from typing import Optional from gi.repository import Gtk, GObject, Adw @@ -138,7 +137,7 @@ def update_progress( self, received_size: int = 0, total_size: int = 0, - status: Optional[Status] = None, + status: Status | None = None, ): if status == Status.FAILED: logging.error("Component installation failed") diff --git a/bottles/frontend/details_dependencies_view.py b/bottles/frontend/details_dependencies_view.py index 217ef84954f..41cc42ce427 100644 --- a/bottles/frontend/details_dependencies_view.py +++ b/bottles/frontend/details_dependencies_view.py @@ -16,7 +16,6 @@ # import time -from typing import Optional from gi.repository import Gtk, GLib, Adw @@ -91,7 +90,7 @@ def empty_list(self): r.get_parent().remove(r) self.__registry = [] - def update(self, _widget=False, config: Optional[BottleConfig] = None): + def update(self, _widget=False, config: BottleConfig | None = None): """ This function update the dependencies list with the supported by the manager. diff --git a/bottles/frontend/details_preferences_page.py b/bottles/frontend/details_preferences_page.py index ee89982dc75..b08dc861aeb 100644 --- a/bottles/frontend/details_preferences_page.py +++ b/bottles/frontend/details_preferences_page.py @@ -456,7 +456,7 @@ def set_config(self, config: BottleConfig): self.entry_name.set_text(config.Name) self.row_cwd.set_subtitle( - _('Directory that contains the data of "{}".'.format(config.Name)) + _(f'Directory that contains the data of "{config.Name}".') ) self.combo_language.set_selected( diff --git a/bottles/frontend/details_task_manager_view.py b/bottles/frontend/details_task_manager_view.py index af55ee80365..d51bca52171 100644 --- a/bottles/frontend/details_task_manager_view.py +++ b/bottles/frontend/details_task_manager_view.py @@ -15,7 +15,6 @@ # along with this program. If not, see . # -from typing import Optional from gi.repository import Gtk @@ -83,14 +82,14 @@ def show_kill_btn(self, widget): return self.btn_kill.set_sensitive(True) - def update(self, widget=False, config: Optional[BottleConfig] = None): + def update(self, widget=False, config: BottleConfig | None = None): """ This function scan for new processed and update the liststore_processes with the new data """ self.liststore_processes.clear() - def fetch_processes(config: Optional[BottleConfig] = None): + def fetch_processes(config: BottleConfig | None = None): if config is None: config = BottleConfig() self.config = config diff --git a/bottles/frontend/gtk.py b/bottles/frontend/gtk.py index dfad76e6552..e01166178de 100644 --- a/bottles/frontend/gtk.py +++ b/bottles/frontend/gtk.py @@ -15,7 +15,6 @@ # along with this program. If not, see . # -from typing import Optional from functools import wraps from inspect import signature @@ -75,7 +74,7 @@ def wrapper(*args, **kwargs): return wrapper @staticmethod - def get_parent_window() -> Optional[GObject.Object]: + def get_parent_window() -> GObject.Object | None: """Retrieve the parent window from a widget.""" toplevels = Gtk.Window.get_toplevels() return toplevels.get_item(0) diff --git a/bottles/frontend/new_bottle_dialog.py b/bottles/frontend/new_bottle_dialog.py index 65718cb799f..7cb47c9dbfb 100644 --- a/bottles/frontend/new_bottle_dialog.py +++ b/bottles/frontend/new_bottle_dialog.py @@ -16,7 +16,7 @@ # from gettext import gettext as _ -from typing import Any, Optional +from typing import Any from gi.repository import Gtk, Adw, Pango, Gio, Xdp, GObject, GLib from bottles.backend.models.config import BottleConfig @@ -231,7 +231,7 @@ def update_output(self, text: str) -> None: self.label_output.set_text(text) @GtkUtils.run_in_main_loop - def finish(self, result: Optional[Result], error=None) -> None: + def finish(self, result: Result | None, error=None) -> None: """Updates widgets based on whether it succeeded or failed.""" def send_notification(notification: Gio.Notification) -> None: diff --git a/bottles/frontend/operation.py b/bottles/frontend/operation.py index 8ed298cc9e3..086519a5e8b 100644 --- a/bottles/frontend/operation.py +++ b/bottles/frontend/operation.py @@ -14,7 +14,6 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . # -from typing import Dict from uuid import UUID from gi.repository import Gtk, Adw @@ -52,7 +51,7 @@ def update(self, subtitle: str): class TaskSyncer: """Keep task list updated with backend TaskManager""" - _TASK_WIDGETS: Dict[UUID, TaskRow] = {} + _TASK_WIDGETS: dict[UUID, TaskRow] = {} def __init__(self, window): self.window = window diff --git a/bottles/frontend/window.py b/bottles/frontend/window.py index 8e05ab88f91..c627e8de9b2 100644 --- a/bottles/frontend/window.py +++ b/bottles/frontend/window.py @@ -19,7 +19,6 @@ import os import webbrowser from gettext import gettext as _ -from typing import Optional from gi.repository import Gtk, GLib, Gio, Adw, GObject, Gdk, Xdp @@ -315,7 +314,7 @@ def send_notification(self, title, text, image="", ignore_user=False): def go_back(self, *_args): self.main_leaf.navigate(direction=Adw.NavigationDirection.BACK) - def show_details_view(self, widget=False, config: Optional[BottleConfig] = None): + def show_details_view(self, widget=False, config: BottleConfig | None = None): self.main_leaf.set_visible_child(self.page_details) self.page_details.set_config(config or BottleConfig()) @@ -352,7 +351,7 @@ def check_crash_log(self): log_path = f"{xdg_data_home}/bottles/crash.log" with contextlib.suppress(FileNotFoundError): - with open(log_path, "r") as log_file: + with open(log_path) as log_file: crash_log = log_file.readlines() os.remove(log_path) diff --git a/bottles/tests/backend/utils/test_generic.py b/bottles/tests/backend/utils/test_generic.py index 1fe1e0765d9..aebd901816b 100644 --- a/bottles/tests/backend/utils/test_generic.py +++ b/bottles/tests/backend/utils/test_generic.py @@ -1,5 +1,3 @@ -from typing import Optional - import pytest from bottles.backend.utils.generic import detect_encoding @@ -21,7 +19,7 @@ ("", None, "utf-8"), ], ) -def test_detect_encoding(text: str, hint: Optional[str], codec: Optional[str]): +def test_detect_encoding(text: str, hint: str | None, codec: str | None): text_bytes = text.encode(codec) guess = detect_encoding(text_bytes, hint) assert guess.lower() == codec.lower() From e733cae1e467050b018dc9f533ebbd619369cb39 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Thu, 16 Jan 2025 19:26:05 -0500 Subject: [PATCH 056/146] chore: Move autoflake above MyPy It makes more sense formatting/cosmetics before type checking. --- .pre-commit-config.yaml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 44316bfa1ef..a75accd478b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -26,14 +26,14 @@ repos: args: [ "--fix" ] - id: ruff-format +- repo: https://github.com/PyCQA/autoflake + rev: v2.3.1 + hooks: + - id: autoflake + - repo: https://github.com/pre-commit/mirrors-mypy rev: v1.13.0 hooks: - id: mypy args: ["--pretty"] additional_dependencies: ["pygobject-stubs", "types-PyYAML", "types-Markdown", "types-requests", "types-pycurl", "types-chardet", "pytest-stub", "types-orjson", "pathvalidate", "requirements-parser", "icoextract", "fvs", "patool", "git+https://gitlab.com/TheEvilSkeleton/vkbasalt-cli.git@main"] - -- repo: https://github.com/PyCQA/autoflake - rev: v2.3.1 - hooks: - - id: autoflake From 4f89c2b58e1a13ae9b6edad3ea84cee9fc4d4abe Mon Sep 17 00:00:00 2001 From: EmoonX Date: Sat, 18 Jan 2025 22:35:53 -0500 Subject: [PATCH 057/146] filters: Introduce `__set_filter` This will be used as a wrapper method for setting filters. Co-authored-by: Hari Rana --- bottles/frontend/filters.py | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/bottles/frontend/filters.py b/bottles/frontend/filters.py index 323dacc106d..1e69446295a 100644 --- a/bottles/frontend/filters.py +++ b/bottles/frontend/filters.py @@ -16,7 +16,7 @@ from gettext import gettext as _ -from gi.repository import Gtk +from gi.repository import Gio, GObject, Gtk def add_executable_filters(dialog): @@ -50,3 +50,21 @@ def add_all_filters(dialog): filter.add_pattern("*") dialog.add_filter(filter) + + +def __set_filter(dialog: GObject.Object, name: str, patterns: list[str]): + """Set dialog named file filter from list of extension patterns.""" + + filter = Gtk.FileFilter() + filter.set_name(name) + for pattern in patterns: + filter.add_pattern(pattern) + + if isinstance(dialog, Gtk.FileDialog): + filters = dialog.get_filters() or Gio.ListStore.new(Gtk.FileFilter) + filters.append(filter) + dialog.set_filters(filters) + elif isinstance(dialog, Gtk.FileChooserNative): + dialog.add_filter(filter) + else: + raise TypeError From c9bef06b5725c4ec8fb74232cfba45b0460b29dc Mon Sep 17 00:00:00 2001 From: EmoonX Date: Sat, 18 Jan 2025 22:40:35 -0500 Subject: [PATCH 058/146] filters: Use `__set_filter` private method to every function Co-authored-by: Hari Rana --- bottles/frontend/filters.py | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/bottles/frontend/filters.py b/bottles/frontend/filters.py index 1e69446295a..509bd850e0b 100644 --- a/bottles/frontend/filters.py +++ b/bottles/frontend/filters.py @@ -20,36 +20,22 @@ def add_executable_filters(dialog): - filter = Gtk.FileFilter() - filter.set_name(_("Supported Executables")) # TODO: Investigate why `filter.add_mime_type(...)` does not show filter in all distributions. # Intended MIME types are: # - `application/x-ms-dos-executable` # - `application/x-msi` - filter.add_pattern("*.exe") - filter.add_pattern("*.msi") - - dialog.add_filter(filter) + __set_filter(dialog, _("Supported Executables"), ["*.exe", "*.msi"]) def add_yaml_filters(dialog): - filter = Gtk.FileFilter() - filter.set_name("YAML") # TODO: Investigate why `filter.add_mime_type(...)` does not show filter in all distributions. # Intended MIME types are: # - `application/yaml` - filter.add_pattern("*.yml") - filter.add_pattern("*.yaml") - - dialog.add_filter(filter) + __set_filter(dialog, "YAML", ["*.yaml", "*.yml"]) def add_all_filters(dialog): - filter = Gtk.FileFilter() - filter.set_name(_("All Files")) - filter.add_pattern("*") - - dialog.add_filter(filter) + __set_filter(dialog, _("All Files"), ["*"]) def __set_filter(dialog: GObject.Object, name: str, patterns: list[str]): From aacc50e67312de4d371387ebda10e1165f8e1372 Mon Sep 17 00:00:00 2001 From: EmoonX Date: Sat, 18 Jan 2025 23:07:22 -0500 Subject: [PATCH 059/146] frontend: Add support for MIDI SoundFont Co-authored-by: Hari Rana --- bottles/frontend/cli.py | 1 + bottles/frontend/filters.py | 4 ++ bottles/frontend/launch-options-dialog.blp | 31 +++++++++++++ bottles/frontend/launch_options_dialog.py | 52 ++++++++++++++++++++++ 4 files changed, 88 insertions(+) diff --git a/bottles/frontend/cli.py b/bottles/frontend/cli.py index d6211929f72..4008ec9e3a6 100644 --- a/bottles/frontend/cli.py +++ b/bottles/frontend/cli.py @@ -670,6 +670,7 @@ def run_program(self): program.get("pre_script", None) program.get("post_script", None) program.get("folder", None) + program.get("midi_soundfont", None) program.get("dxvk") program.get("vkd3d") diff --git a/bottles/frontend/filters.py b/bottles/frontend/filters.py index 509bd850e0b..58b19690371 100644 --- a/bottles/frontend/filters.py +++ b/bottles/frontend/filters.py @@ -27,6 +27,10 @@ def add_executable_filters(dialog): __set_filter(dialog, _("Supported Executables"), ["*.exe", "*.msi"]) +def add_soundfont_filters(dialog): + __set_filter(dialog, _("Supported SoundFonts"), ["*.sf2", "*.sf3"]) + + def add_yaml_filters(dialog): # TODO: Investigate why `filter.add_mime_type(...)` does not show filter in all distributions. # Intended MIME types are: diff --git a/bottles/frontend/launch-options-dialog.blp b/bottles/frontend/launch-options-dialog.blp index ebd35d227ec..e107cab0221 100644 --- a/bottles/frontend/launch-options-dialog.blp +++ b/bottles/frontend/launch-options-dialog.blp @@ -140,6 +140,37 @@ template $LaunchOptionsDialog: Adw.Window { } } } + + Adw.ActionRow action_midi_soundfont { + activatable-widget: btn_midi_soundfont; + title: _("MIDI SoundFont"); + subtitle: _("Choose a custom SoundFont for MIDI playback."); + + Box { + spacing: 6; + + Button btn_midi_soundfont_reset { + tooltip-text: _("Reset to Default"); + valign: center; + visible: false; + icon-name: "edit-undo-symbolic"; + + styles [ + "flat", + ] + } + + Button btn_midi_soundfont { + tooltip-text: _("Choose a SoundFont"); + valign: center; + icon-name: "document-open-symbolic"; + + styles [ + "flat", + ] + } + } + } } Adw.PreferencesGroup { diff --git a/bottles/frontend/launch_options_dialog.py b/bottles/frontend/launch_options_dialog.py index 2fbbbc95944..97c4dc9b25b 100644 --- a/bottles/frontend/launch_options_dialog.py +++ b/bottles/frontend/launch_options_dialog.py @@ -19,6 +19,7 @@ from bottles.backend.utils.manager import ManagerUtils from bottles.backend.logger import Logger +from bottles.frontend.filters import add_all_filters, add_soundfont_filters from gettext import gettext as _ logging = Logger() @@ -40,9 +41,12 @@ class LaunchOptionsDialog(Adw.Window): btn_post_script_reset = Gtk.Template.Child() btn_cwd = Gtk.Template.Child() btn_cwd_reset = Gtk.Template.Child() + btn_midi_soundfont = Gtk.Template.Child() + btn_midi_soundfont_reset = Gtk.Template.Child() btn_reset_defaults = Gtk.Template.Child() action_pre_script = Gtk.Template.Child() action_post_script = Gtk.Template.Child() + action_midi_soundfont = Gtk.Template.Child() switch_dxvk = Gtk.Template.Child() switch_vkd3d = Gtk.Template.Child() switch_nvapi = Gtk.Template.Child() @@ -61,6 +65,7 @@ class LaunchOptionsDialog(Adw.Window): __default_pre_script_msg = _("Choose a script which should be executed before run.") __default_post_script_msg = _("Choose a script which should be executed after run.") __default_cwd_msg = _("Choose from where start the program.") + __default_midi_soundfont_msg = _("Choose a custom SoundFont for MIDI playback.") __msg_disabled = _("{0} is disabled globally for this bottle.") __msg_override = _("This setting overrides the bottle's global setting.") @@ -106,6 +111,8 @@ def __init__(self, parent, config, program, **kwargs): self.btn_pre_script_reset.connect("clicked", self.__reset_pre_script) self.btn_post_script.connect("clicked", self.__choose_post_script) self.btn_post_script_reset.connect("clicked", self.__reset_post_script) + self.btn_midi_soundfont.connect("clicked", self.__choose_midi_soundfont) + self.btn_midi_soundfont_reset.connect("clicked", self.__reset_midi_soundfont) self.btn_cwd.connect("clicked", self.__choose_cwd) self.btn_cwd_reset.connect("clicked", self.__reset_cwd) self.btn_reset_defaults.connect("clicked", self.__reset_defaults) @@ -185,6 +192,10 @@ def __init__(self, parent, config, program, **kwargs): self.action_cwd.set_subtitle(program["folder"]) self.btn_cwd_reset.set_visible(True) + if program.get("midi_soundfont") not in ["", None]: + self.action_midi_soundfont.set_subtitle(program["midi_soundfont"]) + self.btn_midi_soundfont_reset.set_visible(True) + self.__set_disabled_switches() def __check_override(self, widget, state, action, name): @@ -344,6 +355,47 @@ def __reset_cwd(self, *_args): self.action_cwd.set_subtitle(self.__default_cwd_msg) self.btn_cwd_reset.set_visible(False) + def __choose_midi_soundfont(self, *_args): + def set_path(dialog, result): + try: + file = dialog.open_finish(result) + if file is None: + self.action_midi_soundfont.set_subtitle( + self.__default_midi_soundfont_msg + ) + return + + file_path = file.get_path() + self.program["midi_soundfont"] = file_path + self.action_midi_soundfont.set_subtitle(file_path) + self.btn_midi_soundfont_reset.set_visible(True) + + except GLib.Error as error: + # also thrown when dialog has been cancelled + if error.code == 2: + # error 2 seems to be 'dismiss' or 'cancel' + if self.program["midi_soundfont"] in (None, ""): + self.action_midi_soundfont.set_subtitle( + self.__default_midi_soundfont_msg + ) + else: + # something else happened... + logging.warning("Error selecting SoundFont file: %s" % error) + + dialog = Gtk.FileDialog.new() + dialog.set_title(_("Select MIDI SoundFont")) + dialog.set_modal(True) + + add_soundfont_filters(dialog) + add_all_filters(dialog) + + dialog.open(parent=self.window, callback=set_path) + + def __reset_midi_soundfont(self, *_args): + self.program["midi_soundfont"] = None + self.action_midi_soundfont.set_subtitle(self.__default_midi_soundfont_msg) + self.btn_midi_soundfont_reset.set_visible(False) + def __reset_defaults(self, *_args): self.switch_dxvk.set_active(self.global_dxvk) self.switch_vkd3d.set_active(self.global_vkd3d) From 0ecdb4ba5e8e9cb0d3cfc421dc1e195a7a4d1c62 Mon Sep 17 00:00:00 2001 From: EmoonX Date: Sat, 18 Jan 2025 22:52:11 -0500 Subject: [PATCH 060/146] backend: Add support for MIDI SoundFont Co-authored-by: Hari Rana --- .pre-commit-config.yaml | 2 +- bottles/backend/managers/manager.py | 1 + bottles/backend/utils/meson.build | 1 + bottles/backend/utils/midi.py | 45 +++++++++++++++++++++ bottles/backend/wine/executor.py | 10 +++++ bottles/backend/wine/start.py | 2 + bottles/backend/wine/winecommand.py | 4 +- bottles/backend/wine/wineprogram.py | 2 + build-aux/com.usebottles.bottles.Devel.json | 19 +++++++++ build-aux/pypi-deps.yaml | 10 ++++- requirements.txt | 2 + 11 files changed, 95 insertions(+), 3 deletions(-) create mode 100644 bottles/backend/utils/midi.py diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a75accd478b..440e1dd93f4 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -36,4 +36,4 @@ repos: hooks: - id: mypy args: ["--pretty"] - additional_dependencies: ["pygobject-stubs", "types-PyYAML", "types-Markdown", "types-requests", "types-pycurl", "types-chardet", "pytest-stub", "types-orjson", "pathvalidate", "requirements-parser", "icoextract", "fvs", "patool", "git+https://gitlab.com/TheEvilSkeleton/vkbasalt-cli.git@main"] + additional_dependencies: ["pygobject-stubs", "types-PyYAML", "types-Markdown", "types-requests", "types-pycurl", "types-chardet", "pytest-stub", "types-orjson", "pathvalidate", "requirements-parser", "icoextract", "fvs", "patool", "pyfluidsynth", "git+https://gitlab.com/TheEvilSkeleton/vkbasalt-cli.git@main"] diff --git a/bottles/backend/managers/manager.py b/bottles/backend/managers/manager.py index fb4504d1c6d..c3d990c4722 100644 --- a/bottles/backend/managers/manager.py +++ b/bottles/backend/managers/manager.py @@ -725,6 +725,7 @@ def get_programs(self, config: BottleConfig) -> list[dict]: "pre_script": _program.get("pre_script"), "post_script": _program.get("post_script"), "folder": _program.get("folder", program_folder), + "midi_soundfont": _program.get("midi_soundfont"), "dxvk": _program.get("dxvk"), "vkd3d": _program.get("vkd3d"), "dxvk_nvapi": _program.get("dxvk_nvapi"), diff --git a/bottles/backend/utils/meson.build b/bottles/backend/utils/meson.build index 5af7b7011d2..ab74896ff1b 100644 --- a/bottles/backend/utils/meson.build +++ b/bottles/backend/utils/meson.build @@ -6,6 +6,7 @@ bottles_sources = [ 'display.py', 'gpu.py', 'manager.py', + 'midi.py', 'vulkan.py', 'terminal.py', 'file.py', diff --git a/bottles/backend/utils/midi.py b/bottles/backend/utils/midi.py new file mode 100644 index 00000000000..9699b6365e5 --- /dev/null +++ b/bottles/backend/utils/midi.py @@ -0,0 +1,45 @@ +# midi.py +# +# Copyright 2025 The Bottles Contributors +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, in version 3 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + + +from fluidsynth import Synth # type: ignore [import-untyped] + +from bottles.backend.logger import Logger +from bottles.backend.models.config import BottleConfig +from bottles.backend.wine.reg import Reg + +logging = Logger() + + +class FluidSynth: + """FluidSynth instance bound to a SoundFont (.sf2, .sf3) file.""" + + def __init__(self, soundfont_path: str): + """Build a new FluidSynth object from SoundFont file path.""" + self.soundfont_path = soundfont_path + self.__start() + + def __start(self): + """Start FluidSynth synthetizer with loaded SoundFont.""" + logging.info( + "Starting new FluidSynth server with SoundFont" + f" ('{self.soundfont_path}')…" + ) + synth = Synth(channels=16) + synth.start() + sfid = synth.sfload(self.soundfont_path) + synth.program_select(0, sfid, 0, 0) + self.synth = synth diff --git a/bottles/backend/wine/executor.py b/bottles/backend/wine/executor.py index 368fee77aad..cccf6629f4a 100644 --- a/bottles/backend/wine/executor.py +++ b/bottles/backend/wine/executor.py @@ -9,6 +9,7 @@ from bottles.backend.models.config import BottleConfig from bottles.backend.models.result import Result from bottles.backend.utils.manager import ManagerUtils +from bottles.backend.utils.midi import FluidSynth from bottles.backend.wine.cmd import CMD from bottles.backend.wine.explorer import Explorer from bottles.backend.wine.msiexec import MsiExec @@ -33,6 +34,7 @@ def __init__( pre_script: str | None = None, post_script: str | None = None, cwd: str | None = None, + midi_soundfont: str | None = None, monitoring: list | None = None, program_dxvk: bool | None = None, program_vkd3d: bool | None = None, @@ -62,12 +64,16 @@ def __init__( self.pre_script = pre_script self.post_script = post_script self.cwd = self.__get_cwd(cwd) + self.midi_soundfont = midi_soundfont self.monitoring = monitoring self.use_gamescope = program_gamescope self.use_virt_desktop = program_virt_desktop env_dll_overrides = [] + if (soundfont_path := midi_soundfont) not in (None, ""): + FluidSynth(soundfont_path) + # None = use global DXVK value if program_dxvk is not None: # DXVK is globally activated, but disabled for the program @@ -122,6 +128,7 @@ def run_program(cls, config: BottleConfig, program: dict, terminal: bool = False pre_script=program.get("pre_script"), post_script=program.get("post_script"), cwd=program.get("folder"), + midi_soundfont=program.get("midi_soundfont"), terminal=terminal, program_dxvk=program.get("dxvk"), program_vkd3d=program.get("vkd3d"), @@ -212,6 +219,7 @@ def run_cli(self): pre_script=self.pre_script, post_script=self.post_script, cwd=self.cwd, + midi_soundfont=self.midi_soundfont, ) return Result(status=True, data={"output": res}) @@ -278,6 +286,7 @@ def __launch_exe(self): pre_script=self.pre_script, post_script=self.post_script, cwd=self.cwd, + midi_soundfont=self.midi_soundfont, ) res = winecmd.run() self.__set_monitors() @@ -316,6 +325,7 @@ def __launch_with_starter(self): pre_script=self.pre_script, post_script=self.post_script, cwd=self.cwd, + midi_soundfont=self.midi_soundfont, ) self.__set_monitors() return Result(status=True, data={"output": res}) diff --git a/bottles/backend/wine/start.py b/bottles/backend/wine/start.py index 7cde9e5ce6b..d144dae66a4 100644 --- a/bottles/backend/wine/start.py +++ b/bottles/backend/wine/start.py @@ -18,6 +18,7 @@ def run( pre_script: str | None = None, post_script: str | None = None, cwd: str | None = None, + midi_soundfont: str | None = None, ): winepath = WinePath(self.config) @@ -40,6 +41,7 @@ def run( pre_script=pre_script, post_script=post_script, cwd=cwd, + midi_soundfont=midi_soundfont, minimal=False, action_name="run", ) diff --git a/bottles/backend/wine/winecommand.py b/bottles/backend/wine/winecommand.py index 5b62a7b64d9..bf89ff2a6d5 100644 --- a/bottles/backend/wine/winecommand.py +++ b/bottles/backend/wine/winecommand.py @@ -99,6 +99,7 @@ def __init__( pre_script: str | None = None, post_script: str | None = None, cwd: str | None = None, + midi_soundfont: str | None = None, ): _environment = environment.copy() self.config = self._get_config(config) @@ -112,7 +113,7 @@ def __init__( else self.config.Parameters.gamescope ) self.command = self.get_cmd( - command, pre_script, post_script, environment=_environment + command, pre_script, post_script, midi_soundfont, environment=_environment ) self.terminal = terminal self.env = self.get_env(_environment) @@ -488,6 +489,7 @@ def get_cmd( command, pre_script: str | None = None, post_script: str | None = None, + midi_soundfont: str | None = None, return_steam_cmd: bool = False, return_clean_cmd: bool = False, environment: dict | None = None, diff --git a/bottles/backend/wine/wineprogram.py b/bottles/backend/wine/wineprogram.py index 5bcef08b58f..32dd650343b 100644 --- a/bottles/backend/wine/wineprogram.py +++ b/bottles/backend/wine/wineprogram.py @@ -45,6 +45,7 @@ def launch( pre_script: str | None = None, post_script: str | None = None, cwd: str | None = None, + midi_soundfont: str | None = None, action_name: str = "launch", ): if environment is None: @@ -72,6 +73,7 @@ def launch( pre_script=pre_script, post_script=post_script, cwd=cwd, + midi_soundfont=midi_soundfont, arguments=program_args, ) diff --git a/build-aux/com.usebottles.bottles.Devel.json b/build-aux/com.usebottles.bottles.Devel.json index ce153bf51b7..21c31172ca4 100644 --- a/build-aux/com.usebottles.bottles.Devel.json +++ b/build-aux/com.usebottles.bottles.Devel.json @@ -302,6 +302,25 @@ } ] }, + { + "name": "fluidsynth", + "buildsystem": "cmake-ninja", + "cleanup": [ + "/bin", + "/include", + "/lib/cmake", + "/lib/pkgconfig", + "/share/man", + "*.so" + ], + "sources": [ + { + "type": "archive", + "url": "https://github.com/FluidSynth/fluidsynth/archive/v2.3.5.tar.gz", + "sha256": "f89e8e983ecfb4a5b4f5d8c2b9157ed18d15ed2e36246fa782f18abaea550e0d" + } + ] + }, { "name": "libsass", "buildsystem": "meson", diff --git a/build-aux/pypi-deps.yaml b/build-aux/pypi-deps.yaml index 624a86aa9d9..2f505ce35c7 100644 --- a/build-aux/pypi-deps.yaml +++ b/build-aux/pypi-deps.yaml @@ -5,7 +5,7 @@ build-commands: - pip3 install --verbose --exists-action=i --no-index --find-links="file://${PWD}" --prefix=${FLATPAK_DEST} --no-build-isolation wheel PyYAML pycurl chardet requests Markdown icoextract patool pathvalidate FVS orjson pycairo PyGObject charset-normalizer - idna urllib3 certifi pefile + numpy pyfluidsynth idna urllib3 certifi pefile sources: - type: file url: https://files.pythonhosted.org/packages/f7/2f/cc09899755f94b36e7f570b9f9ca19a5fdff536e2614fd3ac1c28bb777f6/FVS-0.3.4.tar.gz @@ -38,6 +38,11 @@ sources: - type: file url: https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl sha256: 946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3 +- type: file + url: https://files.pythonhosted.org/packages/5b/73/65d2f0b698df1731e851e3295eb29a5ab8aa06f763f7e4188647a809578d/numpy-2.2.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl + sha256: 0349b025e15ea9d05c3d63f9657707a4e1d471128a3b1d876c095f328f8ff7f0 + only-arches: + - x86_64 - type: file url: https://files.pythonhosted.org/packages/a0/6b/34e6904ac99df811a06e42d8461d47b6e0c9b86e2fe7ee84934df6e35f0d/orjson-3.10.7-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl sha256: a0c6a008e91d10a2564edbb6ee5069a9e66df3fbe11c9a005cb411f441fd2c09 @@ -60,6 +65,9 @@ sources: sha256: 3d07c5daef2d0d85949e32ec254ee44232bb57febb0634194379dd14d1ff4f87 only-arches: - x86_64 +- type: file + url: https://files.pythonhosted.org/packages/c4/91/4f6b28ac379da306dde66ba6ac170c4a6e7e1506cadc84a9359fe3f237ba/pyfluidsynth-1.3.4-py3-none-any.whl + sha256: c6990329db7cfb35f5e65d523dd4f0c971d928e70df3a6bceec8864827edf246 - type: file url: https://files.pythonhosted.org/packages/f9/9b/335f9764261e915ed497fcdeb11df5dfd6f7bf257d4a6a2a686d80da4d54/requests-2.32.3-py3-none-any.whl sha256: 70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6 diff --git a/requirements.txt b/requirements.txt index c6a2045ae53..a3d1f826e3b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -13,6 +13,8 @@ orjson==3.10.7 pycairo==1.27.0 PyGObject==3.50.0 charset-normalizer==3.3.2 +numpy==2.2.2 +pyfluidsynth==1.3.4 idna==3.10 urllib3==2.2.3 certifi==2024.8.30 From 21967562a273e687085e6aa211e4e8150cde97be Mon Sep 17 00:00:00 2001 From: EmoonX Date: Sun, 19 Jan 2025 13:35:56 -0300 Subject: [PATCH 061/146] backend.midi: Manage FluidSynth instances, avoid duplicates --- bottles/backend/utils/midi.py | 29 +++++++++++++++++++++++++++-- bottles/backend/wine/executor.py | 3 ++- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/bottles/backend/utils/midi.py b/bottles/backend/utils/midi.py index 9699b6365e5..c667a8bc388 100644 --- a/bottles/backend/utils/midi.py +++ b/bottles/backend/utils/midi.py @@ -14,6 +14,7 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . +from typing import Self from fluidsynth import Synth # type: ignore [import-untyped] @@ -25,18 +26,42 @@ class FluidSynth: - """FluidSynth instance bound to a SoundFont (.sf2, .sf3) file.""" + """FluidSynth instance bound to a unique SoundFont (.sf2, .sf3) file path.""" + + __active_instances: dict[int, Self] = {} + + @classmethod + def find_or_create(cls, soundfont_path: str) -> Self: + """ + Search for running FluidSynth instance and return it. + If nonexistent, create and add it to active ones beforehand. + """ + + for fs in cls.__active_instances.values(): + if fs.soundfont_path == soundfont_path: + return fs + + fs = cls(soundfont_path) + cls.__active_instances[fs.id] = fs + return fs def __init__(self, soundfont_path: str): """Build a new FluidSynth object from SoundFont file path.""" self.soundfont_path = soundfont_path + self.id = self.__get_vacant_id() self.__start() + @classmethod + def __get_vacant_id(cls) -> int: + """Get smallest 0-indexed ID currently not in use by a SoundFont.""" + n = len(cls.__active_instances) + return next(i for i in range(n + 1) if i not in cls.__active_instances) + def __start(self): """Start FluidSynth synthetizer with loaded SoundFont.""" logging.info( "Starting new FluidSynth server with SoundFont" - f" ('{self.soundfont_path}')…" + f" #{self.id} ('{self.soundfont_path}')…" ) synth = Synth(channels=16) synth.start() diff --git a/bottles/backend/wine/executor.py b/bottles/backend/wine/executor.py index cccf6629f4a..1087fce46d8 100644 --- a/bottles/backend/wine/executor.py +++ b/bottles/backend/wine/executor.py @@ -71,8 +71,9 @@ def __init__( env_dll_overrides = [] + self.fluidsynth = None if (soundfont_path := midi_soundfont) not in (None, ""): - FluidSynth(soundfont_path) + self.fluidsynth = FluidSynth.find_or_create(soundfont_path) # None = use global DXVK value if program_dxvk is not None: From c3d90a38c68eaf1f263befcde9cf02044c35ee5a Mon Sep 17 00:00:00 2001 From: EmoonX Date: Sun, 19 Jan 2025 13:41:05 -0300 Subject: [PATCH 062/146] backend.midi: Make programs choose the right instrument through registry --- bottles/backend/utils/midi.py | 13 +++++++++++++ bottles/backend/wine/executor.py | 1 + 2 files changed, 14 insertions(+) diff --git a/bottles/backend/utils/midi.py b/bottles/backend/utils/midi.py index c667a8bc388..8fc82b1408c 100644 --- a/bottles/backend/utils/midi.py +++ b/bottles/backend/utils/midi.py @@ -68,3 +68,16 @@ def __start(self): sfid = synth.sfload(self.soundfont_path) synth.program_select(0, sfid, 0, 0) self.synth = synth + + def register_as_current(self, config: BottleConfig): + """ + Update Wine registry with this instance's ID, instructing + MIDI mapping to load the correct instrument set on program startup. + """ + reg = Reg(config) + reg.add( + key="HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Multimedia\\MIDIMap", + value="CurrentInstrument", + data=f"#{self.id}", + value_type="REG_SZ", + ) diff --git a/bottles/backend/wine/executor.py b/bottles/backend/wine/executor.py index 1087fce46d8..1b0071b2dec 100644 --- a/bottles/backend/wine/executor.py +++ b/bottles/backend/wine/executor.py @@ -74,6 +74,7 @@ def __init__( self.fluidsynth = None if (soundfont_path := midi_soundfont) not in (None, ""): self.fluidsynth = FluidSynth.find_or_create(soundfont_path) + self.fluidsynth.register_as_current(config) # None = use global DXVK value if program_dxvk is not None: From 9cb7d06bd580e896be6a794d287e3cadcb59d0f5 Mon Sep 17 00:00:00 2001 From: EmoonX Date: Sun, 19 Jan 2025 13:44:40 -0300 Subject: [PATCH 063/146] backend.midi: Delete instances not in use by any running programs --- bottles/backend/utils/midi.py | 29 ++++++++++++++++++++++++++++- bottles/backend/wine/executor.py | 7 +++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/bottles/backend/utils/midi.py b/bottles/backend/utils/midi.py index 8fc82b1408c..96d8812e958 100644 --- a/bottles/backend/utils/midi.py +++ b/bottles/backend/utils/midi.py @@ -16,7 +16,8 @@ from typing import Self -from fluidsynth import Synth # type: ignore [import-untyped] +from ctypes import c_void_p +from fluidsynth import cfunc, Synth # type: ignore [import-untyped] from bottles.backend.logger import Logger from bottles.backend.models.config import BottleConfig @@ -39,6 +40,7 @@ def find_or_create(cls, soundfont_path: str) -> Self: for fs in cls.__active_instances.values(): if fs.soundfont_path == soundfont_path: + fs.program_count += 1 return fs fs = cls(soundfont_path) @@ -50,6 +52,7 @@ def __init__(self, soundfont_path: str): self.soundfont_path = soundfont_path self.id = self.__get_vacant_id() self.__start() + self.program_count = 1 @classmethod def __get_vacant_id(cls) -> int: @@ -81,3 +84,27 @@ def register_as_current(self, config: BottleConfig): data=f"#{self.id}", value_type="REG_SZ", ) + + def decrement_program_counter(self): + """Decrement program counter; if it reaches zero, delete this instance.""" + self.program_count -= 1 + if self.program_count == 0: + self.__delete() + + def __delete(self): + """Kill underlying synthetizer and remove FluidSynth instance from dict.""" + + def __delete_synth(synth: Synth): + """Bind missing function and run deletion routines.""" + delete_fluid_midi_driver = cfunc( + "delete_fluid_midi_driver", c_void_p, ("driver", c_void_p, 1) + ) + delete_fluid_midi_driver(synth.midi_driver) + synth.delete() + + logging.info( + "Killing FluidSynth server with SoundFont" + f" #{self.id} ('{self.soundfont_path}')…" + ) + __delete_synth(self.synth) + self.__active_instances.pop(self.id) diff --git a/bottles/backend/wine/executor.py b/bottles/backend/wine/executor.py index 1b0071b2dec..f3eaee0d6b2 100644 --- a/bottles/backend/wine/executor.py +++ b/bottles/backend/wine/executor.py @@ -73,6 +73,8 @@ def __init__( self.fluidsynth = None if (soundfont_path := midi_soundfont) not in (None, ""): + # FluidSynth instance is bound to WineExecutor as a member to control + # the former's lifetime (deleted when no more references from executors) self.fluidsynth = FluidSynth.find_or_create(soundfont_path) self.fluidsynth.register_as_current(config) @@ -361,3 +363,8 @@ def __set_monitors(self): winedbg = WineDbg(self.config, silent=True) for m in self.monitoring: winedbg.wait_for_process(name=m) + + def __del__(self): + """On exit, kill FluidSynth instance if this was the last executor using it.""" + if self.fluidsynth: + self.fluidsynth.decrement_program_counter() From 76139e25d935ee8c6db52f23ee75c43caf40bd4a Mon Sep 17 00:00:00 2001 From: EmoonX Date: Sat, 18 Jan 2025 23:02:56 -0500 Subject: [PATCH 064/146] chore: Bump requirements and update pypi-deps --- build-aux/pypi-deps.yaml | 28 ++++++++++++++-------------- requirements.txt | 14 +++++++------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/build-aux/pypi-deps.yaml b/build-aux/pypi-deps.yaml index 2f505ce35c7..858f8177043 100644 --- a/build-aux/pypi-deps.yaml +++ b/build-aux/pypi-deps.yaml @@ -22,14 +22,14 @@ sources: only-arches: - x86_64 - type: file - url: https://files.pythonhosted.org/packages/12/90/3c9ff0512038035f59d279fddeb79f5f1eccd8859f06d6163c58798b9487/certifi-2024.8.30-py3-none-any.whl - sha256: 922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8 + url: https://files.pythonhosted.org/packages/a5/32/8f6669fc4798494966bf446c8c4a162e0b5d893dff088afddf76414f70e1/certifi-2024.12.14-py3-none-any.whl + sha256: 1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56 - type: file url: https://files.pythonhosted.org/packages/38/6f/f5fbc992a329ee4e0f288c1fe0e2ad9485ed064cac731ed2fe47dcc38cbf/chardet-5.2.0-py3-none-any.whl sha256: e1cf59446890a00105fe7b7912492ea04b6e6f06d4b742b2c788469e34c82970 - type: file - url: https://files.pythonhosted.org/packages/ee/fb/14d30eb4956408ee3ae09ad34299131fb383c47df355ddb428a7331cfa1e/charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - sha256: 90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b + url: https://files.pythonhosted.org/packages/3e/a2/513f6cbe752421f16d969e32f3583762bfd583848b763913ddab8d9bfd4f/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl + sha256: bc2722592d8998c870fa4e290c2eec2c1569b87fe58618e67d38b4665dfa680d only-arches: - x86_64 - type: file @@ -44,16 +44,16 @@ sources: only-arches: - x86_64 - type: file - url: https://files.pythonhosted.org/packages/a0/6b/34e6904ac99df811a06e42d8461d47b6e0c9b86e2fe7ee84934df6e35f0d/orjson-3.10.7-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - sha256: a0c6a008e91d10a2564edbb6ee5069a9e66df3fbe11c9a005cb411f441fd2c09 + url: https://files.pythonhosted.org/packages/48/90/e583d6e29937ec30a164f1d86a0439c1a2477b5aae9f55d94b37a4f5b5f0/orjson-3.10.13-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl + sha256: 064b9dbb0217fd64a8d016a8929f2fae6f3312d55ab3036b00b1d17399ab2f3e only-arches: - x86_64 - type: file url: https://files.pythonhosted.org/packages/d3/5e/76a9d08b4b4e4583f269cb9f64de267f9aeae0dacef23307f53a14211716/pathvalidate-3.2.1-py3-none-any.whl sha256: 9a6255eb8f63c9e2135b9be97a5ce08f10230128c4ae7b3e935378b82b22c4c9 - type: file - url: https://files.pythonhosted.org/packages/0e/44/192ede8c7f935643e4c8a56545fcac6ae1b8c50a77f54b2b1c4ab9fcae49/patool-3.0.0-py2.py3-none-any.whl - sha256: 928070d5f82a776534a290a52f4758e2c0dd9cd5a633e3f63f7270c8982833b8 + url: https://files.pythonhosted.org/packages/a3/68/c1a6597c901b1f750d2fcf562181c18c0d6c284908e4df57f1029d8b8887/patool-3.1.0-py2.py3-none-any.whl + sha256: 401a918bdbf65434fd59c038bdb2c15ff7185675aedddb4494330c3e8e4fe80d - type: file url: https://files.pythonhosted.org/packages/54/16/12b82f791c7f50ddec566873d5bdd245baa1491bac11d15ffb98aecc8f8b/pefile-2024.8.26-py3-none-any.whl sha256: 76f8b485dcd3b1bb8166f1128d395fa3d87af26360c2358fb75b80019b957c6f @@ -61,8 +61,8 @@ sources: url: https://files.pythonhosted.org/packages/07/4a/42b26390181a7517718600fa7d98b951da20be982a50cd4afb3d46c2e603/pycairo-1.27.0.tar.gz sha256: 5cb21e7a00a2afcafea7f14390235be33497a2cce53a98a19389492a60628430 - type: file - url: https://files.pythonhosted.org/packages/65/80/8791945007e2295806bfd0e982e00fee023517b17d5b2d845ca64c81878c/pycurl-7.45.3-cp312-cp312-manylinux_2_28_x86_64.whl - sha256: 3d07c5daef2d0d85949e32ec254ee44232bb57febb0634194379dd14d1ff4f87 + url: https://files.pythonhosted.org/packages/2c/4c/07e7192f0d7fc549dab2784c6448ffa98412acb942a365adce4e14d1a143/pycurl-7.45.4-cp312-cp312-manylinux_2_28_x86_64.whl + sha256: 688d09ba2c6a0d4a749d192c43422839d73c40c85143c50cc65c944258fe0ba8 only-arches: - x86_64 - type: file @@ -72,8 +72,8 @@ sources: url: https://files.pythonhosted.org/packages/f9/9b/335f9764261e915ed497fcdeb11df5dfd6f7bf257d4a6a2a686d80da4d54/requests-2.32.3-py3-none-any.whl sha256: 70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6 - type: file - url: https://files.pythonhosted.org/packages/ce/d9/5f4c13cecde62396b0d3fe530a50ccea91e7dfc1ccf0e09c228841bb5ba8/urllib3-2.2.3-py3-none-any.whl - sha256: ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac + url: https://files.pythonhosted.org/packages/c8/19/4ec628951a74043532ca2cf5d97b7b14863931476d117c471e8e2b1eb39f/urllib3-2.3.0-py3-none-any.whl + sha256: 1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df - type: file - url: https://files.pythonhosted.org/packages/1b/d1/9babe2ccaecff775992753d8686970b1e2755d21c8a63be73aba7a4e7d77/wheel-0.44.0-py3-none-any.whl - sha256: 2376a90c98cc337d18623527a97c31797bd02bad0033d41547043a1cbfbe448f + url: https://files.pythonhosted.org/packages/0b/2c/87f3254fd8ffd29e4c02732eee68a83a1d3c346ae39bc6822dcbcb697f2b/wheel-0.45.1-py3-none-any.whl + sha256: 708e7481cc80179af0e556bbf0cc00b8444c7321e2700b8d8580231d13017248 diff --git a/requirements.txt b/requirements.txt index a3d1f826e3b..cf2976c6d36 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,21 +1,21 @@ # Updated using pur -r requirements.txt -wheel==0.44.0 +wheel==0.45.1 PyYAML==6.0.2 -pycurl==7.45.3 +pycurl==7.45.4 chardet==5.2.0 requests[use_chardet_on_py3]==2.32.3 Markdown==3.7 icoextract==0.1.5 -patool==3.0.0 +patool==3.1.0 pathvalidate==3.2.1 FVS==0.3.4 -orjson==3.10.7 +orjson==3.10.13 pycairo==1.27.0 PyGObject==3.50.0 -charset-normalizer==3.3.2 +charset-normalizer==3.4.1 numpy==2.2.2 pyfluidsynth==1.3.4 idna==3.10 -urllib3==2.2.3 -certifi==2024.8.30 +urllib3==2.3.0 +certifi==2024.12.14 pefile==2024.8.26 From 96056559e83f90d34509c2d86e815e31bff7a658 Mon Sep 17 00:00:00 2001 From: "Weblate (bot)" Date: Mon, 20 Jan 2025 14:21:46 +0100 Subject: [PATCH 065/146] Translations update from Hosted Weblate (#3522) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * filters: Introduce `__set_filter` This will be used as a wrapper method for setting filters. Co-authored-by: Hari Rana * filters: Use `__set_filter` private method to every function Co-authored-by: Hari Rana * backend: Add support for MIDI SoundFont Co-authored-by: Hari Rana * frontend: Add support for MIDI SoundFont Co-authored-by: Hari Rana * chore: Bump requirements and update pypi-deps * Translated using Weblate (Portuguese) Currently translated at 100.0% (640 of 640 strings) Translation: Bottles/Bottles Translate-URL: https://hosted.weblate.org/projects/bottles/bottles/pt/ * Translated using Weblate (Hebrew) Currently translated at 26.4% (169 of 640 strings) Translation: Bottles/Bottles Translate-URL: https://hosted.weblate.org/projects/bottles/bottles/he/ * Translated using Weblate (Hebrew) Currently translated at 34.6% (222 of 640 strings) Translation: Bottles/Bottles Translate-URL: https://hosted.weblate.org/projects/bottles/bottles/he/ * Translated using Weblate (Czech) Currently translated at 98.2% (629 of 640 strings) Translation: Bottles/Bottles Translate-URL: https://hosted.weblate.org/projects/bottles/bottles/cs/ * Translated using Weblate (Lithuanian) Currently translated at 12.0% (77 of 640 strings) Translation: Bottles/Bottles Translate-URL: https://hosted.weblate.org/projects/bottles/bottles/lt/ * Added translation using Weblate (Irish) * Translated using Weblate (Irish) Currently translated at 100.0% (677 of 677 strings) Translation: Bottles/Bottles Translate-URL: https://hosted.weblate.org/projects/bottles/bottles/ga/ * Translated using Weblate (Czech) Currently translated at 99.0% (634 of 640 strings) Translation: Bottles/Bottles Translate-URL: https://hosted.weblate.org/projects/bottles/bottles/cs/ * Translated using Weblate (Hebrew) Currently translated at 34.8% (223 of 640 strings) Translation: Bottles/Bottles Translate-URL: https://hosted.weblate.org/projects/bottles/bottles/he/ * Translated using Weblate (Czech) Currently translated at 100.0% (640 of 640 strings) Translation: Bottles/Bottles Translate-URL: https://hosted.weblate.org/projects/bottles/bottles/cs/ * Translated using Weblate (Italian) Currently translated at 100.0% (676 of 676 strings) Translation: Bottles/Bottles Translate-URL: https://hosted.weblate.org/projects/bottles/bottles/it/ * Translated using Weblate (Indonesian) Currently translated at 48.6% (329 of 676 strings) Translation: Bottles/Bottles Translate-URL: https://hosted.weblate.org/projects/bottles/bottles/id/ * Translated using Weblate (Czech) Currently translated at 100.0% (676 of 676 strings) Translation: Bottles/Bottles Translate-URL: https://hosted.weblate.org/projects/bottles/bottles/cs/ * Translated using Weblate (Portuguese) Currently translated at 99.8% (675 of 676 strings) Translation: Bottles/Bottles Translate-URL: https://hosted.weblate.org/projects/bottles/bottles/pt/ * Translated using Weblate (Belarusian) Currently translated at 23.8% (161 of 676 strings) Translation: Bottles/Bottles Translate-URL: https://hosted.weblate.org/projects/bottles/bottles/be/ * Added translation using Weblate (Georgian) * Translated using Weblate (Georgian) Currently translated at 28.9% (197 of 680 strings) Translation: Bottles/Bottles Translate-URL: https://hosted.weblate.org/projects/bottles/bottles/ka/ * Translated using Weblate (Persian) Currently translated at 44.6% (302 of 676 strings) Translation: Bottles/Bottles Translate-URL: https://hosted.weblate.org/projects/bottles/bottles/fa/ * Translated using Weblate (Persian) Currently translated at 55.6% (376 of 676 strings) Translation: Bottles/Bottles Translate-URL: https://hosted.weblate.org/projects/bottles/bottles/fa/ * Translated using Weblate (German) Currently translated at 100.0% (676 of 676 strings) Translation: Bottles/Bottles Translate-URL: https://hosted.weblate.org/projects/bottles/bottles/de/ * Translated using Weblate (Portuguese) Currently translated at 100.0% (676 of 676 strings) Translation: Bottles/Bottles Translate-URL: https://hosted.weblate.org/projects/bottles/bottles/pt/ * Translated using Weblate (Portuguese (Brazil)) Currently translated at 99.8% (675 of 676 strings) Translation: Bottles/Bottles Translate-URL: https://hosted.weblate.org/projects/bottles/bottles/pt_BR/ * Translated using Weblate (Vietnamese) Currently translated at 41.2% (279 of 676 strings) Translation: Bottles/Bottles Translate-URL: https://hosted.weblate.org/projects/bottles/bottles/vi/ * Translated using Weblate (Polish) Currently translated at 98.9% (669 of 676 strings) Translation: Bottles/Bottles Translate-URL: https://hosted.weblate.org/projects/bottles/bottles/pl/ * Translated using Weblate (Hungarian) Currently translated at 97.0% (656 of 676 strings) Translation: Bottles/Bottles Translate-URL: https://hosted.weblate.org/projects/bottles/bottles/hu/ * Translated using Weblate (Finnish) Currently translated at 91.8% (621 of 676 strings) Translation: Bottles/Bottles Translate-URL: https://hosted.weblate.org/projects/bottles/bottles/fi/ * Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (676 of 676 strings) Translation: Bottles/Bottles Translate-URL: https://hosted.weblate.org/projects/bottles/bottles/pt_BR/ * Translated using Weblate (Russian) Currently translated at 100.0% (676 of 676 strings) Translation: Bottles/Bottles Translate-URL: https://hosted.weblate.org/projects/bottles/bottles/ru/ * Translated using Weblate (Polish) Currently translated at 99.7% (674 of 676 strings) Translation: Bottles/Bottles Translate-URL: https://hosted.weblate.org/projects/bottles/bottles/pl/ --------- Co-authored-by: EmoonX Co-authored-by: Hari Rana Co-authored-by: Hugo Carvalho Co-authored-by: Gilad the Grain Co-authored-by: AsciiWolf Co-authored-by: arnas Co-authored-by: Aindriú Mac Giolla Eoin Co-authored-by: Martin Co-authored-by: Yaron Shahrabani Co-authored-by: vikdevelop Co-authored-by: albanobattistella Co-authored-by: Arif Budiman Co-authored-by: Isaac Afonso Co-authored-by: Lang Q Co-authored-by: Temuri Doghonadze Co-authored-by: Danial Behzadi Co-authored-by: Florian Schaupp Co-authored-by: Diego Siqueira Co-authored-by: LucasMZ Co-authored-by: rezarria Co-authored-by: Cezary Frej Co-authored-by: Balázs Meskó Co-authored-by: Ricky Tigg Co-authored-by: John Peter Sa Co-authored-by: Степан Наумов Co-authored-by: PC Co-authored-by: Mirko Brombin --- bottles/backend/utils/midi.py | 2 +- po/LINGUAS | 2 + po/be.po | 242 +-- po/cs.po | 41 +- po/de.po | 25 +- po/fa.po | 485 ++--- po/fi.po | 20 +- po/ga.po | 3231 +++++++++++++++++++++++++++++++++ po/he.po | 456 ++--- po/hu.po | 14 +- po/id.po | 99 +- po/it.po | 20 +- po/ka.po | 3053 +++++++++++++++++++++++++++++++ po/lt.po | 160 +- po/pl.po | 57 +- po/pt.po | 28 +- po/pt_BR.po | 16 +- po/ru.po | 12 +- po/vi.po | 114 +- 19 files changed, 7181 insertions(+), 896 deletions(-) create mode 100644 po/ga.po create mode 100644 po/ka.po diff --git a/bottles/backend/utils/midi.py b/bottles/backend/utils/midi.py index 96d8812e958..a8bce4e8347 100644 --- a/bottles/backend/utils/midi.py +++ b/bottles/backend/utils/midi.py @@ -27,7 +27,7 @@ class FluidSynth: - """FluidSynth instance bound to a unique SoundFont (.sf2, .sf3) file path.""" + """FluidSynth instance bounded to a unique SoundFont (.sf2, .sf3) file.""" __active_instances: dict[int, Self] = {} diff --git a/po/LINGUAS b/po/LINGUAS index 792572d6c32..0a8746d027d 100644 --- a/po/LINGUAS +++ b/po/LINGUAS @@ -47,3 +47,5 @@ be ie az bs +ga +ka diff --git a/po/be.po b/po/be.po index bd5fc575c9d..456cb877198 100644 --- a/po/be.po +++ b/po/be.po @@ -8,17 +8,17 @@ msgstr "" "Project-Id-Version: bottles\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2023-03-27 13:50+0530\n" -"PO-Revision-Date: 2023-09-06 01:41+0000\n" -"Last-Translator: Maksim \n" +"PO-Revision-Date: 2024-12-27 23:25+0000\n" +"Last-Translator: Lang Q \n" "Language-Team: Belarusian \n" "Language: be\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && " -"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" -"X-Generator: Weblate 5.0.1-dev\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && " +"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" +"X-Generator: Weblate 5.10-dev\n" #: bottles/backend/managers/backup.py:48 bottles/backend/managers/backup.py:95 msgid "No path specified" @@ -202,7 +202,7 @@ msgstr "" #: bottles/frontend/main.py:294 msgid "Donate" -msgstr "" +msgstr "Заданаціць" #: bottles/frontend/main.py:299 msgid "Third-Party Libraries and Special Thanks" @@ -210,7 +210,7 @@ msgstr "" #: bottles/frontend/main.py:325 msgid "Sponsored and Funded by" -msgstr "" +msgstr "Спонсарам ды заснавальнікам з'яўляецца" # Translators: Bottles is a proper noun referring to the app #: bottles/frontend/ui/about.blp:5 @@ -228,7 +228,7 @@ msgstr "" #: bottles/frontend/ui/component-entry.blp:4 msgid "Component version" -msgstr "" +msgstr "Версія кампанента" #: bottles/frontend/ui/component-entry.blp:12 #: bottles/frontend/ui/dependency-entry.blp:29 @@ -316,7 +316,7 @@ msgstr "" #: bottles/frontend/ui/details-bottle.blp:33 msgid "Full Backup…" -msgstr "" +msgstr "Полнае рэзервовае капіраванне…" #: bottles/frontend/ui/details-bottle.blp:37 #: bottles/frontend/ui/importer.blp:68 @@ -327,20 +327,20 @@ msgstr "" #: bottles/frontend/ui/details-bottle.blp:38 msgid "Export Configuration…" -msgstr "" +msgstr "Экспарт канфігурацыі…" #: bottles/frontend/ui/details-bottle.blp:45 #: bottles/frontend/views/bottle_details.py:344 msgid "Show Hidden Programs" -msgstr "" +msgstr "Паказаць схаваныя праграмы" #: bottles/frontend/ui/details-bottle.blp:49 msgid "Search for new programs" -msgstr "" +msgstr "Пошук новых праграм" #: bottles/frontend/ui/details-bottle.blp:56 msgid "Delete Bottle…" -msgstr "" +msgstr "Выдаляем Bottle…" #: bottles/frontend/ui/details-bottle.blp:73 #: bottles/frontend/ui/details-dependencies.blp:99 @@ -358,7 +358,7 @@ msgstr "" #: bottles/frontend/ui/details-bottle.blp:95 msgid "Shutdown" -msgstr "" +msgstr "Выключэнне" #: bottles/frontend/ui/details-bottle.blp:99 msgid "Simulate a Windows system reboot." @@ -366,16 +366,16 @@ msgstr "" #: bottles/frontend/ui/details-bottle.blp:100 msgid "Reboot" -msgstr "" +msgstr "Перазагрузка" #: bottles/frontend/ui/details-bottle.blp:118 #: bottles/frontend/ui/dialog-launch-options.blp:6 msgid "Launch Options" -msgstr "" +msgstr "Налады запуску" #: bottles/frontend/ui/details-bottle.blp:135 msgid "Run in Terminal" -msgstr "" +msgstr "Запусціць у тэрмінале" #: bottles/frontend/ui/details-bottle.blp:148 msgid "Drop files to execute them" @@ -392,13 +392,13 @@ msgstr "" #: bottles/frontend/ui/details-bottle.blp:189 #: bottles/frontend/ui/list-entry.blp:12 bottles/frontend/ui/new.blp:71 msgid "Environment" -msgstr "" +msgstr "Наваколле" #: bottles/frontend/ui/details-bottle.blp:201 #: bottles/frontend/ui/details-preferences.blp:14 #: bottles/frontend/ui/new.blp:128 msgid "Runner" -msgstr "" +msgstr "Сродак запуску" #: bottles/frontend/ui/details-bottle.blp:213 #: bottles/frontend/ui/list-entry.blp:21 @@ -412,15 +412,15 @@ msgstr "" #: bottles/frontend/ui/details-bottle.blp:227 #: bottles/frontend/ui/list-entry.blp:31 msgid "0" -msgstr "" +msgstr "0" #: bottles/frontend/ui/details-bottle.blp:247 msgid "Run Executable…" -msgstr "" +msgstr "Запусціць выканаўчы файл…" #: bottles/frontend/ui/details-bottle.blp:272 msgid "Programs" -msgstr "" +msgstr "Праграмы" #: bottles/frontend/ui/details-bottle.blp:275 msgid "" @@ -431,20 +431,20 @@ msgstr "" #: bottles/frontend/ui/details-bottle.blp:298 msgid "Add Shortcuts…" -msgstr "" +msgstr "Дадаць ярлыкі…" #: bottles/frontend/ui/details-bottle.blp:325 msgid "Install Programs…" -msgstr "" +msgstr "Усталяваць праграмы…" #: bottles/frontend/ui/details-bottle.blp:346 msgid "Options" -msgstr "" +msgstr "Параметры" #: bottles/frontend/ui/details-bottle.blp:350 #: bottles/frontend/views/details.py:141 msgid "Settings" -msgstr "" +msgstr "Налады" #: bottles/frontend/ui/details-bottle.blp:351 msgid "Configure bottle settings." @@ -453,17 +453,17 @@ msgstr "" #: bottles/frontend/ui/details-bottle.blp:360 #: bottles/frontend/views/details.py:145 msgid "Dependencies" -msgstr "" +msgstr "Залежнасці" #: bottles/frontend/ui/details-bottle.blp:361 msgid "Install dependencies for programs." -msgstr "" +msgstr "Усталяваць залежнасці для праграм." #: bottles/frontend/ui/details-bottle.blp:370 #: bottles/frontend/ui/details-preferences.blp:377 #: bottles/frontend/views/details.py:149 msgid "Snapshots" -msgstr "" +msgstr "Снапшоты" #: bottles/frontend/ui/details-bottle.blp:371 msgid "Create and manage bottle states." @@ -473,19 +473,19 @@ msgstr "" #: bottles/frontend/ui/details-bottle.blp:426 #: bottles/frontend/views/details.py:157 msgid "Task Manager" -msgstr "" +msgstr "Менеджэр" #: bottles/frontend/ui/details-bottle.blp:381 msgid "Manage running programs." -msgstr "" +msgstr "Настроіць запушчаныя праграмы." #: bottles/frontend/ui/details-bottle.blp:390 msgid "Tools" -msgstr "" +msgstr "Інструменты" #: bottles/frontend/ui/details-bottle.blp:394 msgid "Command Line" -msgstr "" +msgstr "Камандны Радок" #: bottles/frontend/ui/details-bottle.blp:395 msgid "Run commands inside the Bottle." @@ -505,7 +505,7 @@ msgstr "" #: bottles/frontend/ui/details-bottle.blp:417 msgid "Explorer" -msgstr "" +msgstr "Файл Менеджэр" #: bottles/frontend/ui/details-bottle.blp:435 msgid "Debugger" @@ -514,15 +514,15 @@ msgstr "" #: bottles/frontend/ui/details-bottle.blp:444 #: bottles/frontend/ui/importer.blp:69 bottles/frontend/ui/new.blp:145 msgid "Configuration" -msgstr "" +msgstr "Канфігурацыя" #: bottles/frontend/ui/details-bottle.blp:453 msgid "Uninstaller" -msgstr "" +msgstr "Дэінсталятар" #: bottles/frontend/ui/details-bottle.blp:462 msgid "Control Panel" -msgstr "" +msgstr "Панель кіравання" #: bottles/frontend/ui/details-dependencies.blp:9 msgid "Search for dependencies…" @@ -532,7 +532,7 @@ msgstr "" #: bottles/frontend/ui/preferences.blp:178 #: bottles/frontend/ui/preferences.blp:235 msgid "You're offline :(" -msgstr "" +msgstr "У вас няма інтэрнет-падключэння! :(" #: bottles/frontend/ui/details-dependencies.blp:25 msgid "Bottles is running in offline mode, so dependencies are not available." @@ -556,23 +556,23 @@ msgstr "" #: bottles/frontend/ui/details-dependencies.blp:81 msgid "Read Documentation." -msgstr "" +msgstr "Прачытаць дакументацыю." #: bottles/frontend/ui/details-dependencies.blp:82 #: bottles/frontend/ui/details-installers.blp:51 #: bottles/frontend/ui/details-versioning.blp:37 msgid "Documentation" -msgstr "" +msgstr "Дакументацыя" #: bottles/frontend/ui/details-dependencies.blp:92 #: bottles/frontend/ui/details-installers.blp:61 #: bottles/frontend/ui/window.blp:46 msgid "Search" -msgstr "" +msgstr "Пошук" #: bottles/frontend/ui/details-installers.blp:9 msgid "Search for Programs…" -msgstr "" +msgstr "Пошук праграм…" #: bottles/frontend/ui/details-installers.blp:15 msgid "" @@ -584,7 +584,7 @@ msgstr "" #: bottles/frontend/ui/details-installers.blp:29 msgid "No Installers Found" -msgstr "" +msgstr "Устаноўшчыкаў не знойдзена" #: bottles/frontend/ui/details-installers.blp:32 msgid "" @@ -595,16 +595,16 @@ msgstr "" #: bottles/frontend/ui/details-versioning.blp:36 #: bottles/frontend/ui/preferences.blp:81 msgid "Read Documentation" -msgstr "" +msgstr "Чытаць Дакуменатцыю" #: bottles/frontend/ui/details-preferences.blp:6 #: bottles/frontend/ui/dialog-duplicate.blp:52 msgid "Name" -msgstr "" +msgstr "Назва" #: bottles/frontend/ui/details-preferences.blp:11 msgid "Components" -msgstr "" +msgstr "Кампаненты" #: bottles/frontend/ui/details-preferences.blp:15 #: bottles/frontend/ui/new.blp:129 @@ -613,7 +613,7 @@ msgstr "" #: bottles/frontend/ui/details-preferences.blp:17 msgid "Updating Runner and components, please wait…" -msgstr "" +msgstr "Абнаўленне сродка запуску і кампанентаў, пачакайце, калі ласка…" #: bottles/frontend/ui/details-preferences.blp:27 #: bottles/frontend/ui/preferences.blp:262 @@ -626,7 +626,7 @@ msgstr "" #: bottles/frontend/ui/details-preferences.blp:30 msgid "Updating DXVK, please wait…" -msgstr "" +msgstr "Абнаўленне DXVK, пачакайце, калі ласка…" #: bottles/frontend/ui/details-preferences.blp:40 #: bottles/frontend/ui/preferences.blp:266 @@ -639,7 +639,7 @@ msgstr "" #: bottles/frontend/ui/details-preferences.blp:43 msgid "Updating VKD3D, please wait…" -msgstr "" +msgstr "Абнаўленне VKD3D, пачакайце, калі ласка…" #: bottles/frontend/ui/details-preferences.blp:54 msgid "DXVK NVAPI" @@ -648,7 +648,7 @@ msgstr "" #: bottles/frontend/ui/details-preferences.blp:58 #: bottles/frontend/ui/details-preferences.blp:93 msgid "Updating DXVK-NVAPI, please wait…" -msgstr "" +msgstr "Абнаўленне DXVK-NVAPI, пачакайце, калі ласка…" #: bottles/frontend/ui/details-preferences.blp:68 #: bottles/frontend/ui/preferences.blp:274 @@ -661,11 +661,11 @@ msgstr "" #: bottles/frontend/ui/details-preferences.blp:71 msgid "Updating LatencyFleX, please wait…" -msgstr "" +msgstr "Абнаўленне LatencyFleX, пачакайце, калі ласка…" #: bottles/frontend/ui/details-preferences.blp:84 msgid "Display" -msgstr "" +msgstr "Дісплэй" #: bottles/frontend/ui/details-preferences.blp:88 msgid "Deep Learning Super Sampling" @@ -691,7 +691,7 @@ msgstr "" #: bottles/frontend/ui/details-preferences.blp:125 msgid "Discrete Graphics" -msgstr "" +msgstr "Діскрэтная Графіка" #: bottles/frontend/ui/details-preferences.blp:126 msgid "" @@ -722,11 +722,11 @@ msgstr "" #: bottles/frontend/ui/details-preferences.blp:171 msgid "Advanced Display Settings" -msgstr "" +msgstr "Дадатковыя налады дісплэя" #: bottles/frontend/ui/details-preferences.blp:184 msgid "Performance" -msgstr "" +msgstr "Прадукцыйнасць" #: bottles/frontend/ui/details-preferences.blp:188 msgid "Enable synchronization to increase performance of multicore processors." @@ -734,11 +734,11 @@ msgstr "" #: bottles/frontend/ui/details-preferences.blp:189 msgid "Synchronization" -msgstr "" +msgstr "Сінхранізацыя" #: bottles/frontend/ui/details-preferences.blp:193 msgid "System" -msgstr "" +msgstr "Сістэма" #: bottles/frontend/ui/details-preferences.blp:194 msgid "Esync" @@ -754,7 +754,7 @@ msgstr "" #: bottles/frontend/ui/details-preferences.blp:202 msgid "Monitor Performance" -msgstr "" +msgstr "Прадукцыйнасць манітора" #: bottles/frontend/ui/details-preferences.blp:203 msgid "" @@ -773,7 +773,7 @@ msgstr "" #: bottles/frontend/ui/details-preferences.blp:221 msgid "Preload Game Files" -msgstr "" +msgstr "Загадзя загрузіць файлы гульні" #: bottles/frontend/ui/details-preferences.blp:222 msgid "" @@ -795,23 +795,23 @@ msgstr "" #: bottles/frontend/ui/details-preferences.blp:251 msgid "Compatibility" -msgstr "" +msgstr "Сумяшчальнасць" #: bottles/frontend/ui/details-preferences.blp:254 msgid "Windows Version" -msgstr "" +msgstr "Версія Windows" #: bottles/frontend/ui/details-preferences.blp:257 msgid "Updating Windows version, please wait…" -msgstr "" +msgstr "Абнаўленне Windows, пачакайце, калі ласка…" #: bottles/frontend/ui/details-preferences.blp:266 msgid "Language" -msgstr "" +msgstr "Мова" #: bottles/frontend/ui/details-preferences.blp:267 msgid "Choose the language to use with programs." -msgstr "" +msgstr "Абярыце мову для выкарыстоўвання з праграмамі." #: bottles/frontend/ui/details-preferences.blp:275 msgid "Dedicated Sandbox" @@ -823,12 +823,12 @@ msgstr "" #: bottles/frontend/ui/details-preferences.blp:279 msgid "Manage the Sandbox Permissions" -msgstr "" +msgstr "Змяніць права пясочніцы" # Translators: Bottles is a proper noun referring to the app #: bottles/frontend/ui/details-preferences.blp:295 msgid "Bottles Runtime" -msgstr "" +msgstr "Час выконвання (Bottles)" #: bottles/frontend/ui/details-preferences.blp:296 msgid "" @@ -838,7 +838,7 @@ msgstr "" #: bottles/frontend/ui/details-preferences.blp:306 msgid "Steam Runtime" -msgstr "" +msgstr "Час выконвання (Steam)" #: bottles/frontend/ui/details-preferences.blp:307 msgid "" @@ -849,7 +849,7 @@ msgstr "" #: bottles/frontend/ui/details-preferences.blp:315 #: bottles/frontend/ui/dialog-launch-options.blp:83 msgid "Working Directory" -msgstr "" +msgstr "Рабочая дэрыкторыя" #: bottles/frontend/ui/details-preferences.blp:318 #: bottles/frontend/ui/dialog-launch-options.blp:59 @@ -857,13 +857,13 @@ msgstr "" #: bottles/frontend/ui/new.blp:150 bottles/frontend/ui/new.blp:181 #: bottles/frontend/ui/preferences.blp:136 msgid "Reset to Default" -msgstr "" +msgstr "Сбросіць да стана па-умаўчанні" #: bottles/frontend/ui/details-preferences.blp:339 #: bottles/frontend/ui/preferences.blp:157 bottles/frontend/views/new.py:78 #: bottles/frontend/views/preferences.py:210 msgid "(Default)" -msgstr "" +msgstr "(Па-умаўчанні)" #: bottles/frontend/ui/details-preferences.blp:347 #: bottles/frontend/ui/dialog-dll-overrides.blp:7 @@ -874,7 +874,7 @@ msgstr "" #: bottles/frontend/ui/details-preferences.blp:357 #: bottles/frontend/ui/dialog-env-vars.blp:20 msgid "Environment Variables" -msgstr "" +msgstr "Пераменныя Наваколля" #: bottles/frontend/ui/details-preferences.blp:367 msgid "Manage Drives" @@ -892,7 +892,7 @@ msgstr "" #: bottles/frontend/ui/details-preferences.blp:391 msgid "Compression" -msgstr "" +msgstr "Сцісканне" #: bottles/frontend/ui/details-preferences.blp:392 msgid "" @@ -914,15 +914,15 @@ msgstr "" #: bottles/frontend/ui/details-taskmanager.blp:17 msgid "Refresh" -msgstr "" +msgstr "Перазагрузіць" #: bottles/frontend/ui/details-taskmanager.blp:22 msgid "Stop process" -msgstr "" +msgstr "Спыніць працэс" #: bottles/frontend/ui/details-versioning.blp:18 msgid "No Snapshots Found" -msgstr "" +msgstr "Снапшотаў не знойдзена" #: bottles/frontend/ui/details-versioning.blp:19 msgid "Create your first snapshot to start saving states of your preferences." @@ -930,7 +930,7 @@ msgstr "" #: bottles/frontend/ui/details-versioning.blp:54 msgid "A short comment" -msgstr "" +msgstr "Кароткі каментар" #: bottles/frontend/ui/details-versioning.blp:58 msgid "Save the bottle state." @@ -947,11 +947,11 @@ msgstr "" #: bottles/frontend/ui/details.blp:24 bottles/frontend/ui/details.blp:64 #: bottles/frontend/ui/importer.blp:15 msgid "Go Back" -msgstr "" +msgstr "Назад" #: bottles/frontend/ui/details.blp:75 msgid "Operations" -msgstr "" +msgstr "Аперацыі" #: bottles/frontend/ui/dialog-bottle-picker.blp:4 msgid "Select Bottle" @@ -962,11 +962,11 @@ msgstr "" #: bottles/frontend/ui/dialog-rename.blp:15 #: bottles/frontend/ui/dialog-run-args.blp:20 msgid "Cancel" -msgstr "" +msgstr "Скасаваць" #: bottles/frontend/ui/dialog-bottle-picker.blp:21 msgid "Select" -msgstr "" +msgstr "Абраць" #: bottles/frontend/ui/dialog-bottle-picker.blp:38 #: bottles/frontend/ui/new.blp:9 bottles/frontend/ui/new.blp:49 @@ -990,7 +990,7 @@ msgstr "" #: bottles/frontend/views/bottle_preferences.py:749 #: bottles/frontend/views/preferences.py:201 msgid "_Cancel" -msgstr "" +msgstr "Скасаваць" #: bottles/frontend/ui/dialog-crash-report.blp:25 msgid "Send Report" @@ -1016,7 +1016,7 @@ msgstr "" #: bottles/frontend/ui/dialog-crash-report.blp:95 msgid "Advanced options" -msgstr "" +msgstr "Дадатковыя налады" #: bottles/frontend/ui/dialog-deps-check.blp:13 msgid "Incomplete package" @@ -1031,7 +1031,7 @@ msgstr "" #: bottles/frontend/ui/dialog-deps-check.blp:18 msgid "Quit" -msgstr "" +msgstr "Выйсці" #: bottles/frontend/ui/dialog-dll-overrides.blp:11 msgid "" @@ -1059,7 +1059,7 @@ msgstr "" #: bottles/frontend/ui/dialog-drives.blp:27 msgid "Letter" -msgstr "" +msgstr "Ліст" #: bottles/frontend/ui/dialog-drives.blp:49 msgid "Existing Drives" @@ -1100,11 +1100,11 @@ msgstr "" #: bottles/frontend/ui/dialog-env-vars.blp:31 msgid "Variable Name" -msgstr "" +msgstr "Назва пераменнай" #: bottles/frontend/ui/dialog-env-vars.blp:37 msgid "Existing Variables" -msgstr "" +msgstr "Існыя пераменныя" #: bottles/frontend/ui/dialog-exclusion-patterns.blp:20 msgid "Exclusion Patterns" @@ -1133,7 +1133,7 @@ msgstr "" #: bottles/frontend/ui/dialog-rename.blp:20 #: bottles/frontend/ui/dialog-vkbasalt.blp:34 msgid "Save" -msgstr "" +msgstr "Захаваць" #: bottles/frontend/ui/dialog-gamescope.blp:40 msgid "Manage how games should be displayed." @@ -1141,7 +1141,7 @@ msgstr "" #: bottles/frontend/ui/dialog-gamescope.blp:44 msgid "Game Resolution" -msgstr "" +msgstr "Разрознасць у гульні" #: bottles/frontend/ui/dialog-gamescope.blp:45 msgid "Uses the resolution of the video game as a reference in pixels." @@ -1150,16 +1150,16 @@ msgstr "" #: bottles/frontend/ui/dialog-gamescope.blp:48 #: bottles/frontend/ui/dialog-gamescope.blp:85 msgid "Width" -msgstr "" +msgstr "Шырыня" #: bottles/frontend/ui/dialog-gamescope.blp:64 #: bottles/frontend/ui/dialog-gamescope.blp:101 msgid "Height" -msgstr "" +msgstr "Вышыня" #: bottles/frontend/ui/dialog-gamescope.blp:81 msgid "Window Resolution" -msgstr "" +msgstr "Разрознасць акна" #: bottles/frontend/ui/dialog-gamescope.blp:82 msgid "" @@ -1173,7 +1173,7 @@ msgstr "" #: bottles/frontend/ui/dialog-gamescope.blp:121 msgid "Frame Rate Limit" -msgstr "" +msgstr "Ліміт частаты кадраў" #: bottles/frontend/ui/dialog-gamescope.blp:137 msgid "Frame Rate Limit When Unfocused" @@ -1185,7 +1185,7 @@ msgstr "" #: bottles/frontend/ui/dialog-gamescope.blp:162 msgid "Window Type" -msgstr "" +msgstr "Тып акна" #: bottles/frontend/ui/dialog-gamescope.blp:166 msgid "Borderless" @@ -1193,7 +1193,7 @@ msgstr "" #: bottles/frontend/ui/dialog-gamescope.blp:172 msgid "Fullscreen" -msgstr "" +msgstr "Паўнаэкранны" #: bottles/frontend/ui/dialog-installer.blp:40 msgid "Do you want to proceed with the installation?" @@ -1201,7 +1201,7 @@ msgstr "" #: bottles/frontend/ui/dialog-installer.blp:45 msgid "Start Installation" -msgstr "" +msgstr "Пачаць устаноўку" #: bottles/frontend/ui/dialog-installer.blp:64 msgid "" @@ -1211,27 +1211,27 @@ msgstr "" #: bottles/frontend/ui/dialog-installer.blp:68 msgid "Proceed" -msgstr "" +msgstr "Прыступіць" #: bottles/frontend/ui/dialog-installer.blp:127 msgid "Completed!" -msgstr "" +msgstr "Выканана!" #: bottles/frontend/ui/dialog-installer.blp:130 msgid "Show Programs" -msgstr "" +msgstr "Паказаць праграмы" #: bottles/frontend/ui/dialog-installer.blp:148 msgid "Installation Failed!" -msgstr "" +msgstr "Устаноўка не выканана!" #: bottles/frontend/ui/dialog-installer.blp:149 msgid "Something went wrong." -msgstr "" +msgstr "Нешта пайшло не так." #: bottles/frontend/ui/dialog-journal.blp:9 msgid "All messages" -msgstr "" +msgstr "Усе паведамленні" #: bottles/frontend/ui/dialog-journal.blp:13 msgid "Critical" @@ -1239,15 +1239,15 @@ msgstr "" #: bottles/frontend/ui/dialog-journal.blp:17 msgid "Errors" -msgstr "" +msgstr "Памылкі" #: bottles/frontend/ui/dialog-journal.blp:21 msgid "Warnings" -msgstr "" +msgstr "Папярэджванне" #: bottles/frontend/ui/dialog-journal.blp:25 msgid "Info" -msgstr "" +msgstr "Інфармацыя" #: bottles/frontend/ui/dialog-journal.blp:40 msgid "Journal browser" @@ -1263,7 +1263,7 @@ msgstr "" #: bottles/frontend/ui/dialog-journal.blp:57 msgid "All" -msgstr "" +msgstr "Усе" #: bottles/frontend/ui/dialog-launch-options.blp:42 msgid "Those arguments will be passed at launch." @@ -1275,7 +1275,7 @@ msgstr "" #: bottles/frontend/ui/dialog-launch-options.blp:46 msgid "Command Arguments" -msgstr "" +msgstr "Аргументы каманды" #: bottles/frontend/ui/dialog-launch-options.blp:47 #, c-format @@ -1294,17 +1294,17 @@ msgstr "" #: bottles/frontend/ui/dialog-launch-options.blp:70 msgid "Choose a Script" -msgstr "" +msgstr "Абярыце скрыпт" #: bottles/frontend/ui/dialog-launch-options.blp:84 #: bottles/frontend/windows/launchoptions.py:55 msgid "Choose from where start the program." -msgstr "" +msgstr "Абярыце, адкуль пачаць праграму." #: bottles/frontend/ui/dialog-launch-options.blp:101 #: bottles/frontend/ui/drive-entry.blp:22 msgid "Choose a Directory" -msgstr "" +msgstr "Абярэцые дэрыкторыю" #: bottles/frontend/ui/dialog-launch-options.blp:114 msgid "These settings will override the default settings for this executable." @@ -1351,25 +1351,25 @@ msgstr "" #: bottles/frontend/ui/dialog-rename.blp:7 msgid "Rename" -msgstr "" +msgstr "Перайменаваць" #: bottles/frontend/ui/dialog-rename.blp:30 msgid "Choose a new name for the selected program." -msgstr "" +msgstr "Абярыце новае імя для гэтай праграмы." #: bottles/frontend/ui/dialog-rename.blp:33 msgid "New Name" -msgstr "" +msgstr "Новае імя" #: bottles/frontend/ui/dialog-run-args.blp:13 msgid "Run With Arguments" -msgstr "" +msgstr "Запусціць з аргументамі" #: bottles/frontend/ui/dialog-run-args.blp:34 #: bottles/frontend/views/bottle_details.py:401 #: bottles/frontend/views/list.py:131 msgid "Run" -msgstr "" +msgstr "Запусціць" #: bottles/frontend/ui/dialog-run-args.blp:44 msgid "Write below the arguments to be passed to the executable." @@ -1381,7 +1381,7 @@ msgstr "" #: bottles/frontend/ui/dialog-sandbox.blp:7 msgid "Sandbox Settings" -msgstr "" +msgstr "Налады пясочніцы" #: bottles/frontend/ui/dialog-sandbox.blp:25 msgid "Share Network" @@ -1398,7 +1398,7 @@ msgstr "" #: bottles/frontend/ui/dialog-upgrade-versioning.blp:38 #: bottles/frontend/ui/onboard.blp:81 msgid "Continue" -msgstr "" +msgstr "Працягнуць" #: bottles/frontend/ui/dialog-upgrade-versioning.blp:47 msgid "Launch upgrade" @@ -1442,11 +1442,11 @@ msgstr "" #: bottles/frontend/ui/dialog-vkbasalt.blp:44 msgid "Default" -msgstr "" +msgstr "Па-умаўчанні" #: bottles/frontend/ui/dialog-vkbasalt.blp:48 msgid "Default Settings" -msgstr "" +msgstr "Налады па-умаўчанні" #: bottles/frontend/ui/dialog-vkbasalt.blp:57 msgid "Effects are applied according to the list order." @@ -1454,7 +1454,7 @@ msgstr "" #: bottles/frontend/ui/dialog-vkbasalt.blp:58 msgid "Effects" -msgstr "" +msgstr "Эфекты" #: bottles/frontend/ui/dialog-vkbasalt.blp:62 msgid "Contrast Adaptive Sharpening" @@ -1477,7 +1477,7 @@ msgstr "" #: bottles/frontend/ui/dialog-vkbasalt.blp:343 #: bottles/frontend/ui/dialog-vkbasalt.blp:370 bottles/frontend/ui/new.blp:58 msgid "Show Information" -msgstr "" +msgstr "Паказаць інфармацыю" #. Translators: Luma is not translatable #: bottles/frontend/ui/dialog-vkbasalt.blp:99 @@ -1518,7 +1518,7 @@ msgstr "" #: bottles/frontend/ui/dialog-vkbasalt.blp:273 msgid "Color" -msgstr "" +msgstr "Колер" #: bottles/frontend/ui/dialog-vkbasalt.blp:284 msgid "Threshold" diff --git a/po/cs.po b/po/cs.po index cf3ec8f3561..23aa355032f 100644 --- a/po/cs.po +++ b/po/cs.po @@ -8,16 +8,16 @@ msgstr "" "Project-Id-Version: bottles\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2023-03-27 13:50+0530\n" -"PO-Revision-Date: 2024-09-16 08:09+0000\n" -"Last-Translator: Zezik \n" +"PO-Revision-Date: 2024-12-19 20:43+0000\n" +"Last-Translator: vikdevelop \n" "Language-Team: Czech \n" "Language: cs\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" -"X-Generator: Weblate 5.8-dev\n" +"Plural-Forms: nplurals=3; plural=((n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2);\n" +"X-Generator: Weblate 5.9.2-dev\n" #: bottles/backend/managers/backup.py:48 bottles/backend/managers/backup.py:95 msgid "No path specified" @@ -3061,24 +3061,23 @@ msgstr "Opraveno tlačítko \"Přidat do Steamu\"" #: data/com.usebottles.bottles.metainfo.xml.in:95 msgid "Fixed BottleConfig being not serializable" -msgstr "" +msgstr "Opraven problém, kde BottleConfig nemohl být serializován" #: data/com.usebottles.bottles.metainfo.xml.in:96 msgid "Fixed Patool double extraction failing" -msgstr "" +msgstr "Opraveno selhání dvojité extrakce Patool" #: data/com.usebottles.bottles.metainfo.xml.in:101 msgid "Correct version" msgstr "Správná verze" #: data/com.usebottles.bottles.metainfo.xml.in:106 -#, fuzzy msgid "Fix crash when creating a bottle" -msgstr "Při vytváření láhve se vyskytla chyba." +msgstr "Vyřešen pád programu při vytváření láhve" #: data/com.usebottles.bottles.metainfo.xml.in:111 msgid "Major change: Redesign New Bottle interface" -msgstr "" +msgstr "Hlavní změna: Změna designu Hlavního Uživatelského Rozhraní Lahví" #: data/com.usebottles.bottles.metainfo.xml.in:112 msgid "Quality of life improvements:" @@ -3086,12 +3085,11 @@ msgstr "Drobná vylepšení uživatelského rozhraní:" #: data/com.usebottles.bottles.metainfo.xml.in:114 msgid "Replace emote-love icon with library in library page" -msgstr "" +msgstr "Nahrazení ikony emotikony lásky ikonou knihovny na stránce knihovny" #: data/com.usebottles.bottles.metainfo.xml.in:115 -#, fuzzy msgid "Add toast for \"Run Executable\"" -msgstr "Přidání vlastní cesty ke spustitelnému souboru" +msgstr "Přidat vyskakovací okno pro \"Spustit spustitelný soubor\"" #: data/com.usebottles.bottles.metainfo.xml.in:117 msgid "Bug fixes:" @@ -3099,7 +3097,7 @@ msgstr "Opravy chyb:" #: data/com.usebottles.bottles.metainfo.xml.in:119 msgid "Adding shortcut to Steam resulted an error" -msgstr "" +msgstr "Přidání zástupce do služby Steam vedlo k chybě" #: data/com.usebottles.bottles.metainfo.xml.in:120 msgid "Importing backups resulted an error" @@ -3114,6 +3112,8 @@ msgid "" "Various library related fixes, like empty covers, and crashes related to " "missing entries" msgstr "" +"Různé opravy související s knihovnami, například prázdné obálky a pády " +"související s chybějícími položkami" #: data/com.usebottles.bottles.metainfo.xml.in:123 msgid "Fix various issues related to text encoding" @@ -3130,6 +3130,7 @@ msgstr "Správné datum verze" #: data/com.usebottles.bottles.metainfo.xml.in:138 msgid "Hide NVIDIA-related critical errors on non NVIDIA systems" msgstr "" +"Skrytí kritických chyb souvisejících s NVIDIA v systémech jiných než NVIDIA" #: data/com.usebottles.bottles.metainfo.xml.in:145 msgid "Gamescope improvements and fixes" @@ -3141,7 +3142,7 @@ msgstr "Instalace závislostí je rychlejší a stabilnější" #: data/com.usebottles.bottles.metainfo.xml.in:147 msgid "The health check has more information for faster debugging" -msgstr "" +msgstr "Kontrola stavu obsahuje více informací pro rychlejší ladění" #: data/com.usebottles.bottles.metainfo.xml.in:148 msgid "NVAPI has a lot of fixes and is more stable, should now work properly" @@ -3153,19 +3154,21 @@ msgstr "Oprava chyby při stahování komponenty" #: data/com.usebottles.bottles.metainfo.xml.in:150 msgid "Backend code improvement by avoiding spin-lock" -msgstr "" +msgstr "Zlepšení kódu backendu zamezením spin-locku" #: data/com.usebottles.bottles.metainfo.xml.in:151 msgid "More variables for installer scripting" -msgstr "" +msgstr "Více proměnných pro skriptování instalátoru" #: data/com.usebottles.bottles.metainfo.xml.in:152 msgid "Fix onboard dialog showing \"All ready\" while it was in fact not ready" msgstr "" +"Oprava dialogového okna na palubě zobrazujícího „Vše připraveno“, i když ve " +"skutečnosti připraveno nebylo" #: data/com.usebottles.bottles.metainfo.xml.in:153 msgid "Improvement to build system" -msgstr "" +msgstr "Vylepšení v build systému" #: data/com.usebottles.bottles.metainfo.xml.in:154 msgid "Enabling VKD3D by default when creating bottles for gaming" @@ -3173,13 +3176,15 @@ msgstr "Automatické povolení VKD3D při tvorbě Lahve pro hry" #: data/com.usebottles.bottles.metainfo.xml.in:155 msgid "Fix crashes when reading Steam files with bad encodings" -msgstr "" +msgstr "Oprava pádů při čtení souborů služby Steam se špatným kódováním" #: data/com.usebottles.bottles.metainfo.xml.in:156 msgid "" "Fix components not updated correctly in the UI after installation/" "uninstallation" msgstr "" +"Oprava komponent, které se po instalaci/odinstalaci správně neaktualizují v " +"uživatelském rozhraní" #: data/com.usebottles.bottles.metainfo.xml.in:157 msgid "More FSR fixes" diff --git a/po/de.po b/po/de.po index 22704fb541e..6fdea2e0356 100644 --- a/po/de.po +++ b/po/de.po @@ -8,8 +8,8 @@ msgstr "" "Project-Id-Version: bottles\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2023-03-27 13:50+0530\n" -"PO-Revision-Date: 2024-04-21 13:07+0000\n" -"Last-Translator: David \n" +"PO-Revision-Date: 2024-12-30 04:00+0000\n" +"Last-Translator: Florian Schaupp \n" "Language-Team: German \n" "Language: de\n" @@ -17,7 +17,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 5.5-dev\n" +"X-Generator: Weblate 5.10-dev\n" #: bottles/backend/managers/backup.py:48 bottles/backend/managers/backup.py:95 msgid "No path specified" @@ -1033,7 +1033,7 @@ msgstr "Neue Bottle erstellen" # Translators: Bottles is a proper noun referring to the app #: bottles/frontend/ui/dialog-crash-report.blp:8 msgid "Bottles Crash Report" -msgstr "Bottles Absturzbericht" +msgstr "Bottles-Absturzbericht" #: bottles/frontend/ui/dialog-crash-report.blp:18 #: bottles/frontend/ui/dialog-duplicate.blp:22 @@ -1241,8 +1241,8 @@ msgid "" "Upscales the resolution when using a resolution higher than the game " "resolution in pixels." msgstr "" -"Erhöht die Auflösung, wenn eine Auflösung verwendet wird, die höher ist als " -"die Spielauflösung in Pixel." +"Erhöht die Auflösung, wenn eine höhere Auflösung als die Spielauflösung in " +"Pixel verwendet wird." #: bottles/frontend/ui/dialog-gamescope.blp:118 msgid "Miscellaneous" @@ -1935,7 +1935,6 @@ msgid "C_reate" msgstr "E_rstellen" #: bottles/frontend/ui/new.blp:53 -#, fuzzy msgid "Bottle Name" msgstr "Bottle-Name" @@ -3130,7 +3129,7 @@ msgstr "Absturz beim Erstellen einer Bottle behoben" #: data/com.usebottles.bottles.metainfo.xml.in:111 msgid "Major change: Redesign New Bottle interface" -msgstr "Große Änderung: Neugestaltung der neuen Bottles oberfläche" +msgstr "Große Änderung: Neugestaltung der neuen Bottles Oberfläche" #: data/com.usebottles.bottles.metainfo.xml.in:112 msgid "Quality of life improvements:" @@ -3138,7 +3137,7 @@ msgstr "Verbesserung der Nutzererfahrung:" #: data/com.usebottles.bottles.metainfo.xml.in:114 msgid "Replace emote-love icon with library in library page" -msgstr "" +msgstr "Herz-Emoji durch Bibliothek Icon auf der Bibliothek Seite ersetzt" #: data/com.usebottles.bottles.metainfo.xml.in:115 msgid "Add toast for \"Run Executable\"" @@ -3150,7 +3149,7 @@ msgstr "Fehlerbehebungen:" #: data/com.usebottles.bottles.metainfo.xml.in:119 msgid "Adding shortcut to Steam resulted an error" -msgstr "" +msgstr "Beim Hinzufügen der Steam-Verknüpfung ist ein Fehler aufgetreten" #: data/com.usebottles.bottles.metainfo.xml.in:120 msgid "Importing backups resulted an error" @@ -3166,6 +3165,8 @@ msgid "" "Various library related fixes, like empty covers, and crashes related to " "missing entries" msgstr "" +"Diverse Reparaturen betreffend die Bibliothek, beispielsweise leere Symbole " +"oder Abstürze aufgrund fehlenden Einträgen" #: data/com.usebottles.bottles.metainfo.xml.in:123 msgid "Fix various issues related to text encoding" @@ -3183,7 +3184,7 @@ msgstr "Korrektes Versionsdatum" #: data/com.usebottles.bottles.metainfo.xml.in:138 msgid "Hide NVIDIA-related critical errors on non NVIDIA systems" -msgstr "" +msgstr "NVIDIA bezogene, kritische Fehler auf nicht-NVIDIA Systemen ausblenden" #: data/com.usebottles.bottles.metainfo.xml.in:145 msgid "Gamescope improvements and fixes" @@ -3220,6 +3221,8 @@ msgstr "Weitere Variablen für die Skripterstellung des Installationsprogramms" #: data/com.usebottles.bottles.metainfo.xml.in:152 msgid "Fix onboard dialog showing \"All ready\" while it was in fact not ready" msgstr "" +"Korrektur des Einrichtungs-Dialogs. Dieser hat \"Alles Bereit\" angezeigt, " +"obwohl die Einrichtung noch nicht abgeschlossen war" #: data/com.usebottles.bottles.metainfo.xml.in:153 msgid "Improvement to build system" diff --git a/po/fa.po b/po/fa.po index d353d2de433..b0ea78329f5 100644 --- a/po/fa.po +++ b/po/fa.po @@ -8,7 +8,7 @@ msgstr "" "Project-Id-Version: bottles\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2023-03-27 13:50+0530\n" -"PO-Revision-Date: 2024-09-20 00:40+0000\n" +"PO-Revision-Date: 2024-12-28 22:49+0000\n" "Last-Translator: Danial Behzadi \n" "Language-Team: Persian \n" @@ -17,7 +17,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n > 1;\n" -"X-Generator: Weblate 5.8-dev\n" +"X-Generator: Weblate 5.10-dev\n" #: bottles/backend/managers/backup.py:48 bottles/backend/managers/backup.py:95 msgid "No path specified" @@ -26,7 +26,7 @@ msgstr "هیچ مسیری مشخّص نشده" #: bottles/backend/managers/backup.py:56 #, python-brace-format msgid "Backup {0}" -msgstr "" +msgstr "پشتیبان گیری از {0}" #: bottles/backend/managers/backup.py:101 #, python-brace-format @@ -72,7 +72,7 @@ msgstr "" #: bottles/backend/managers/manager.py:1209 msgid "Sandboxing userdir…" -msgstr "" +msgstr "گودال ماسه سازی از شاخهٔ کاربری…" #: bottles/backend/managers/manager.py:1250 msgid "Setting Windows version…" @@ -84,7 +84,7 @@ msgstr "" #: bottles/backend/managers/manager.py:1268 msgid "Optimizing environment…" -msgstr "" +msgstr "بهینه سازی محیط…" #: bottles/backend/managers/manager.py:1279 #, python-brace-format @@ -101,15 +101,15 @@ msgstr "" #: bottles/backend/managers/manager.py:1309 msgid "Installing DXVK…" -msgstr "" +msgstr "نصب کردن DXVK…" #: bottles/backend/managers/manager.py:1317 msgid "Installing VKD3D…" -msgstr "" +msgstr "نصب کردن VKD3D…" #: bottles/backend/managers/manager.py:1326 msgid "Installing DXVK-NVAPI…" -msgstr "" +msgstr "نصب کردن DXVK-NVAPI…" #: bottles/backend/managers/manager.py:1335 #, python-format @@ -122,11 +122,11 @@ msgstr "" #: bottles/backend/managers/manager.py:1353 msgid "Finalizing…" -msgstr "" +msgstr "پایان بندی…" #: bottles/backend/managers/manager.py:1364 msgid "Caching template…" -msgstr "" +msgstr "انبارش الگو…" #: bottles/backend/managers/versioning.py:83 msgid "Committing state …" @@ -155,9 +155,8 @@ msgid "Restoring state {} …" msgstr "" #: bottles/backend/managers/versioning.py:162 -#, fuzzy msgid "State not found" -msgstr "حذف کننده" +msgstr "وضعیت پیدا نشد" #: bottles/backend/managers/versioning.py:168 msgid "State {} is already the active state" @@ -182,7 +181,7 @@ msgstr "نام بطری" #: bottles/frontend/main.py:144 msgid "Pass arguments" -msgstr "" +msgstr "فرستادن آرگومان‌ها" #: bottles/frontend/main.py:203 msgid "Invalid URI (syntax: bottles:run//)" @@ -214,15 +213,13 @@ msgstr "" # Translators: Bottles is a proper noun referring to the app #: bottles/frontend/ui/about.blp:5 -#, fuzzy msgid "Copyright © 2017 Bottles Developers" -msgstr "© ۲۰۱۷-۲۰۲۲ - توسعه دهندگان Bottles" +msgstr "حق رونوشت © ۲۰۱۷ توسعه دهندگان بطری‌ها" # Translators: Bottles is a proper noun referring to the app #: bottles/frontend/ui/about.blp:10 -#, fuzzy msgid "Bottles Developers" -msgstr "© ۲۰۱۷-۲۰۲۲ - توسعه دهندگان Bottles" +msgstr "توسعه دهندگان بطری‌ها" #: bottles/frontend/ui/about.blp:12 msgid "translator_credits" @@ -239,9 +236,8 @@ msgid "Uninstall" msgstr "حذف نصب" #: bottles/frontend/ui/component-entry.blp:23 -#, fuzzy msgid "Browse Files" -msgstr "مرور فایل ها" +msgstr "مرور پرونده‌ها" #: bottles/frontend/ui/component-entry.blp:34 msgid "" @@ -251,7 +247,7 @@ msgstr "" #: bottles/frontend/ui/component-entry.blp:45 msgid "Download & Install" -msgstr "دانلود و نصب" +msgstr "بارگیری و نصب" #: bottles/frontend/ui/component-entry.blp:58 msgid "0%" @@ -259,7 +255,7 @@ msgstr "۰٪" #: bottles/frontend/ui/dependency-entry.blp:16 msgid "Show Manifest" -msgstr "" +msgstr "نمایش بیانیه" #: bottles/frontend/ui/dependency-entry.blp:20 msgid "License" @@ -267,29 +263,28 @@ msgstr "مجوز" #: bottles/frontend/ui/dependency-entry.blp:24 msgid "Reinstall" -msgstr "نصب مجدد" +msgstr "نصب دوباره" #: bottles/frontend/ui/dependency-entry.blp:36 #: bottles/frontend/ui/installer-entry.blp:27 msgid "Report a Bug…" -msgstr "" +msgstr "گزارش اشکال…" #: bottles/frontend/ui/dependency-entry.blp:42 msgid "Dependency name" -msgstr "" +msgstr "نام وابستگی" #: bottles/frontend/ui/dependency-entry.blp:44 msgid "Dependency description" -msgstr "" +msgstr "شرح وابستگی" #: bottles/frontend/ui/dependency-entry.blp:51 msgid "Category" msgstr "دسته" #: bottles/frontend/ui/dependency-entry.blp:64 -#, fuzzy msgid "Download & Install this Dependency" -msgstr "دانلود و نصب وابستگی‌ها" +msgstr "بارگیری و نصب وابستگی‌ها" #: bottles/frontend/ui/dependency-entry.blp:79 msgid "" @@ -299,11 +294,11 @@ msgstr "" #: bottles/frontend/ui/dependency-entry.blp:93 msgid "Dependency Menu" -msgstr "" +msgstr "فهرست وابستگی" #: bottles/frontend/ui/details-bottle.blp:16 msgid "Troubleshooting" -msgstr "" +msgstr "اشکال‌زدایی" #: bottles/frontend/ui/details-bottle.blp:24 msgid "Browse Files…" @@ -320,7 +315,7 @@ msgstr "" #: bottles/frontend/ui/details-bottle.blp:33 msgid "Full Backup…" -msgstr "" +msgstr "پشتبان کامل…" #: bottles/frontend/ui/details-bottle.blp:37 #: bottles/frontend/ui/importer.blp:68 @@ -335,14 +330,12 @@ msgstr "برون‌ریزی پیکربندی…" #: bottles/frontend/ui/details-bottle.blp:45 #: bottles/frontend/views/bottle_details.py:344 -#, fuzzy msgid "Show Hidden Programs" -msgstr "نمایش/مخفی سازی برنامه های حذف شده" +msgstr "نمایش برنامه‌های نهفته" #: bottles/frontend/ui/details-bottle.blp:49 -#, fuzzy msgid "Search for new programs" -msgstr "جست و جو برای برنامه های نصب شده" +msgstr "جست‌وجوی برنامه‌های جدید" #: bottles/frontend/ui/details-bottle.blp:56 msgid "Delete Bottle…" @@ -352,7 +345,7 @@ msgstr "حذف بطری…" #: bottles/frontend/ui/details-dependencies.blp:99 #: bottles/frontend/ui/details-installers.blp:68 msgid "Secondary Menu" -msgstr "" +msgstr "فهرست ثانویه" #: bottles/frontend/ui/details-bottle.blp:90 msgid "Force Stop all Processes" @@ -376,27 +369,24 @@ msgstr "راه اندازی مجدد" #: bottles/frontend/ui/details-bottle.blp:118 #: bottles/frontend/ui/dialog-launch-options.blp:6 -#, fuzzy msgid "Launch Options" -msgstr "گزینه های پیشرفته" +msgstr "گزینه‌های اجرا" #: bottles/frontend/ui/details-bottle.blp:135 -#, fuzzy msgid "Run in Terminal" -msgstr "اجرا با ترمینال" +msgstr "اجرا در پایانه" #: bottles/frontend/ui/details-bottle.blp:148 msgid "Drop files to execute them" msgstr "" #: bottles/frontend/ui/details-bottle.blp:164 -#, fuzzy msgid "My bottle" -msgstr "حذف Bottle" +msgstr "بطری‌هایم" #: bottles/frontend/ui/details-bottle.blp:177 msgid "Win64" -msgstr "" +msgstr "Win64" #: bottles/frontend/ui/details-bottle.blp:189 #: bottles/frontend/ui/list-entry.blp:12 bottles/frontend/ui/new.blp:71 @@ -425,7 +415,7 @@ msgstr "۰" #: bottles/frontend/ui/details-bottle.blp:247 msgid "Run Executable…" -msgstr "" +msgstr "اجرای پرونده…" #: bottles/frontend/ui/details-bottle.blp:272 msgid "Programs" @@ -440,7 +430,7 @@ msgstr "" #: bottles/frontend/ui/details-bottle.blp:298 msgid "Add Shortcuts…" -msgstr "" +msgstr "افزودن میان‌برها…" #: bottles/frontend/ui/details-bottle.blp:325 msgid "Install Programs…" @@ -482,7 +472,7 @@ msgstr "" #: bottles/frontend/ui/details-bottle.blp:426 #: bottles/frontend/views/details.py:157 msgid "Task Manager" -msgstr "" +msgstr "مدیر وظیفه" #: bottles/frontend/ui/details-bottle.blp:381 msgid "Manage running programs." @@ -494,15 +484,15 @@ msgstr "ابزارها" #: bottles/frontend/ui/details-bottle.blp:394 msgid "Command Line" -msgstr "" +msgstr "خط فرمان" #: bottles/frontend/ui/details-bottle.blp:395 msgid "Run commands inside the Bottle." -msgstr "" +msgstr "اجرای فرمان‌ها درون بطری." #: bottles/frontend/ui/details-bottle.blp:404 msgid "Registry Editor" -msgstr "" +msgstr "ویرایشگر رجیستری" #: bottles/frontend/ui/details-bottle.blp:405 msgid "Edit the internal registry." @@ -518,7 +508,7 @@ msgstr "کاوشگر" #: bottles/frontend/ui/details-bottle.blp:435 msgid "Debugger" -msgstr "" +msgstr "اشکال‌زدا" #: bottles/frontend/ui/details-bottle.blp:444 #: bottles/frontend/ui/importer.blp:69 bottles/frontend/ui/new.blp:145 @@ -535,13 +525,13 @@ msgstr "" #: bottles/frontend/ui/details-dependencies.blp:9 msgid "Search for dependencies…" -msgstr "" +msgstr "جست‌وجوی وابستگی‌ها…" #: bottles/frontend/ui/details-dependencies.blp:22 #: bottles/frontend/ui/preferences.blp:178 #: bottles/frontend/ui/preferences.blp:235 msgid "You're offline :(" -msgstr "" +msgstr "برون خطید :(" #: bottles/frontend/ui/details-dependencies.blp:25 msgid "Bottles is running in offline mode, so dependencies are not available." @@ -561,7 +551,7 @@ msgstr "" #: bottles/frontend/ui/details-dependencies.blp:77 msgid "Report Missing Dependency" -msgstr "" +msgstr "گزارش وابستگی غایب" #: bottles/frontend/ui/details-dependencies.blp:81 msgid "Read Documentation." @@ -592,9 +582,8 @@ msgid "" msgstr "" #: bottles/frontend/ui/details-installers.blp:29 -#, fuzzy msgid "No Installers Found" -msgstr "حذف کننده" +msgstr "هیچ نصب کننده‌ای پیدا نشد" #: bottles/frontend/ui/details-installers.blp:32 msgid "" @@ -604,9 +593,8 @@ msgstr "" #: bottles/frontend/ui/details-installers.blp:50 #: bottles/frontend/ui/details-versioning.blp:36 #: bottles/frontend/ui/preferences.blp:81 -#, fuzzy msgid "Read Documentation" -msgstr "مطالعه مستندات" +msgstr "خواندن مستندات" #: bottles/frontend/ui/details-preferences.blp:6 #: bottles/frontend/ui/dialog-duplicate.blp:52 @@ -629,7 +617,7 @@ msgstr "" #: bottles/frontend/ui/details-preferences.blp:27 #: bottles/frontend/ui/preferences.blp:262 msgid "DXVK" -msgstr "" +msgstr "DXVK" #: bottles/frontend/ui/details-preferences.blp:28 msgid "Improve Direct3D 8/9/10/11 compatibility by translating it to Vulkan." @@ -642,7 +630,7 @@ msgstr "" #: bottles/frontend/ui/details-preferences.blp:40 #: bottles/frontend/ui/preferences.blp:266 msgid "VKD3D" -msgstr "" +msgstr "VKD3D" #: bottles/frontend/ui/details-preferences.blp:41 msgid "Improve Direct3D 12 compatibility by translating it to Vulkan." @@ -654,7 +642,7 @@ msgstr "" #: bottles/frontend/ui/details-preferences.blp:54 msgid "DXVK NVAPI" -msgstr "" +msgstr "DXVK NVAPI" #: bottles/frontend/ui/details-preferences.blp:58 #: bottles/frontend/ui/details-preferences.blp:93 @@ -664,16 +652,15 @@ msgstr "" #: bottles/frontend/ui/details-preferences.blp:68 #: bottles/frontend/ui/preferences.blp:274 msgid "LatencyFleX" -msgstr "" +msgstr "LatencyFleX" #: bottles/frontend/ui/details-preferences.blp:69 msgid "Increase responsiveness. Can be detected by some anti-cheat software." msgstr "" #: bottles/frontend/ui/details-preferences.blp:71 -#, fuzzy msgid "Updating LatencyFleX, please wait…" -msgstr "در حال بروزرسانی نسخه ویندوز، لطفا صبر کنید…" +msgstr "به‌روز رساندن LatencyFleX. لطفاً شکیبا باشید…" #: bottles/frontend/ui/details-preferences.blp:84 msgid "Display" @@ -691,7 +678,7 @@ msgstr "" #: bottles/frontend/ui/details-preferences.blp:105 msgid "FidelityFX Super Resolution" -msgstr "" +msgstr "ابروضوح FidelityFX" #: bottles/frontend/ui/details-preferences.blp:106 msgid "Increase performance at the expense of visuals. Only works on Vulkan." @@ -702,9 +689,8 @@ msgid "Manage FidelityFX Super Resolution settings" msgstr "" #: bottles/frontend/ui/details-preferences.blp:125 -#, fuzzy msgid "Discrete Graphics" -msgstr "گرافیک" +msgstr "گرافیک اختصاصی" #: bottles/frontend/ui/details-preferences.blp:126 msgid "" @@ -714,7 +700,7 @@ msgstr "" #: bottles/frontend/ui/details-preferences.blp:135 msgid "Post-Processing Effects" -msgstr "" +msgstr "جلوه‌های پس از پردازش" #: bottles/frontend/ui/details-preferences.blp:136 msgid "" @@ -734,9 +720,8 @@ msgid "Manage Gamescope settings" msgstr "" #: bottles/frontend/ui/details-preferences.blp:171 -#, fuzzy msgid "Advanced Display Settings" -msgstr "تنظیمات نمایش" +msgstr "تنظیمات نمایش پیش‌رفته" #: bottles/frontend/ui/details-preferences.blp:184 msgid "Performance" @@ -756,20 +741,19 @@ msgstr "سیستم" #: bottles/frontend/ui/details-preferences.blp:194 msgid "Esync" -msgstr "" +msgstr "Esync" #: bottles/frontend/ui/details-preferences.blp:195 msgid "Fsync" -msgstr "" +msgstr "Fsync" #: bottles/frontend/ui/details-preferences.blp:196 msgid "Futex2" -msgstr "" +msgstr "Futex2" #: bottles/frontend/ui/details-preferences.blp:202 -#, fuzzy msgid "Monitor Performance" -msgstr "عملکرد" +msgstr "عملکرد نمایشگر" #: bottles/frontend/ui/details-preferences.blp:203 msgid "" @@ -778,9 +762,8 @@ msgid "" msgstr "" #: bottles/frontend/ui/details-preferences.blp:211 -#, fuzzy msgid "Feral GameMode" -msgstr "استفاده از GameMode" +msgstr "حالت بازی Feral" #: bottles/frontend/ui/details-preferences.blp:212 msgid "" @@ -814,13 +797,12 @@ msgid "Compatibility" msgstr "سازگاری" #: bottles/frontend/ui/details-preferences.blp:254 -#, fuzzy msgid "Windows Version" -msgstr "نسخه ویندوز" +msgstr "نگارش ویندوز" #: bottles/frontend/ui/details-preferences.blp:257 msgid "Updating Windows version, please wait…" -msgstr "در حال بروزرسانی نسخه ویندوز، لطفا صبر کنید…" +msgstr "به‌روز کردن نگارش ویندوز. لطفاً‌ شکیبا باشید…" #: bottles/frontend/ui/details-preferences.blp:266 msgid "Language" @@ -832,7 +814,7 @@ msgstr "" #: bottles/frontend/ui/details-preferences.blp:275 msgid "Dedicated Sandbox" -msgstr "" +msgstr "گودال ماسهٔ اختصاصی" #: bottles/frontend/ui/details-preferences.blp:276 msgid "Use a restricted/managed environment for this bottle." @@ -867,16 +849,15 @@ msgstr "" #: bottles/frontend/ui/details-preferences.blp:315 #: bottles/frontend/ui/dialog-launch-options.blp:83 msgid "Working Directory" -msgstr "" +msgstr "شاخهٔ کاری" #: bottles/frontend/ui/details-preferences.blp:318 #: bottles/frontend/ui/dialog-launch-options.blp:59 #: bottles/frontend/ui/dialog-launch-options.blp:90 #: bottles/frontend/ui/new.blp:150 bottles/frontend/ui/new.blp:181 #: bottles/frontend/ui/preferences.blp:136 -#, fuzzy msgid "Reset to Default" -msgstr "بطری‌ها" +msgstr "بازنشانی به پیش‌گزیده" #: bottles/frontend/ui/details-preferences.blp:339 #: bottles/frontend/ui/preferences.blp:157 bottles/frontend/views/new.py:78 @@ -888,23 +869,20 @@ msgstr "(پیش‌گزیده)" #: bottles/frontend/ui/dialog-dll-overrides.blp:7 #: bottles/frontend/ui/dialog-dll-overrides.blp:12 msgid "DLL Overrides" -msgstr "" +msgstr "پایمالی DLLها" #: bottles/frontend/ui/details-preferences.blp:357 #: bottles/frontend/ui/dialog-env-vars.blp:20 -#, fuzzy msgid "Environment Variables" -msgstr "افزودن سریع متغییر های محیطی" +msgstr "متغیّرهای محیطی" #: bottles/frontend/ui/details-preferences.blp:367 -#, fuzzy msgid "Manage Drives" -msgstr "مدیریت درایو ها" +msgstr "مدیریت گرداننده‌ها" #: bottles/frontend/ui/details-preferences.blp:381 -#, fuzzy msgid "Automatic Snapshots" -msgstr "نسخه سازی بطری‌ها ( اختیاری )" +msgstr "عکس‌های فوری خودکار" #: bottles/frontend/ui/details-preferences.blp:382 msgid "" @@ -931,9 +909,8 @@ msgid "Exclude paths in snapshots." msgstr "" #: bottles/frontend/ui/details-preferences.blp:405 -#, fuzzy msgid "Manage Patterns" -msgstr "مدیریت درایو ها" +msgstr "مدیریت الگوها" #: bottles/frontend/ui/details-taskmanager.blp:17 msgid "Refresh" @@ -944,9 +921,8 @@ msgid "Stop process" msgstr "توقّف فرایند" #: bottles/frontend/ui/details-versioning.blp:18 -#, fuzzy msgid "No Snapshots Found" -msgstr "حذف کننده" +msgstr "هیچ عکس فوری‌ای پیدا نشد" #: bottles/frontend/ui/details-versioning.blp:19 msgid "Create your first snapshot to start saving states of your preferences." @@ -961,9 +937,8 @@ msgid "Save the bottle state." msgstr "" #: bottles/frontend/ui/details-versioning.blp:78 -#, fuzzy msgid "Create new Snapshot" -msgstr "بطری‌ها" +msgstr "ایجاد عکس فوری جدید" #: bottles/frontend/ui/details.blp:16 msgid "Details" @@ -971,18 +946,16 @@ msgstr "جزییات" #: bottles/frontend/ui/details.blp:24 bottles/frontend/ui/details.blp:64 #: bottles/frontend/ui/importer.blp:15 -#, fuzzy msgid "Go Back" -msgstr "برگشت" +msgstr "بازگشت" #: bottles/frontend/ui/details.blp:75 msgid "Operations" msgstr "عملیات" #: bottles/frontend/ui/dialog-bottle-picker.blp:4 -#, fuzzy msgid "Select Bottle" -msgstr "حذف Bottle" +msgstr "گزینش بطری" #: bottles/frontend/ui/dialog-bottle-picker.blp:16 #: bottles/frontend/ui/dialog-proton-alert.blp:16 @@ -998,9 +971,8 @@ msgstr "گزینش" #: bottles/frontend/ui/dialog-bottle-picker.blp:38 #: bottles/frontend/ui/new.blp:9 bottles/frontend/ui/new.blp:49 #: bottles/frontend/ui/window.blp:25 -#, fuzzy msgid "Create New Bottle" -msgstr "بطری‌ها" +msgstr "ایجاد بطری جدید" # Translators: Bottles is a proper noun referring to the app #: bottles/frontend/ui/dialog-crash-report.blp:8 @@ -1021,9 +993,8 @@ msgid "_Cancel" msgstr "_لغو" #: bottles/frontend/ui/dialog-crash-report.blp:25 -#, fuzzy msgid "Send Report" -msgstr "ارسال گزارش" +msgstr "فرستادن گزارش" #: bottles/frontend/ui/dialog-crash-report.blp:44 msgid "" @@ -1041,7 +1012,7 @@ msgstr "" #: bottles/frontend/ui/dialog-crash-report.blp:89 msgid "I still want to report." -msgstr "" +msgstr "هنوز می‌خواهم گزارش دهم." #: bottles/frontend/ui/dialog-crash-report.blp:95 msgid "Advanced options" @@ -1049,7 +1020,7 @@ msgstr "گزینه های پیشرفته" #: bottles/frontend/ui/dialog-deps-check.blp:13 msgid "Incomplete package" -msgstr "" +msgstr "بستهٔ ناقص" #: bottles/frontend/ui/dialog-deps-check.blp:14 msgid "" @@ -1069,13 +1040,12 @@ msgid "" msgstr "" #: bottles/frontend/ui/dialog-dll-overrides.blp:15 -#, fuzzy msgid "New Override" -msgstr "متغیر جدید" +msgstr "پایمالی جدید" #: bottles/frontend/ui/dialog-dll-overrides.blp:21 msgid "Overrides" -msgstr "" +msgstr "پایمالی‌ها" #: bottles/frontend/ui/dialog-drives.blp:7 msgid "Drives" @@ -1089,21 +1059,19 @@ msgstr "" #: bottles/frontend/ui/dialog-drives.blp:27 msgid "Letter" -msgstr "" +msgstr "حرف" #: bottles/frontend/ui/dialog-drives.blp:49 -#, fuzzy msgid "Existing Drives" -msgstr "درایو های موجود" +msgstr "گرداننده‌های موجود" #: bottles/frontend/ui/dialog-duplicate.blp:16 -#, fuzzy msgid "Duplicate Bottle" -msgstr "حذف Bottle" +msgstr "تکثیر بطری" #: bottles/frontend/ui/dialog-duplicate.blp:38 msgid "Duplicate" -msgstr "" +msgstr "تکثیر" #: bottles/frontend/ui/dialog-duplicate.blp:49 msgid "Enter a name for the duplicate of the Bottle." @@ -1111,18 +1079,18 @@ msgstr "ورود نامی برای دوقلوی بطری." #: bottles/frontend/ui/dialog-duplicate.blp:69 msgid "Duplicating…" -msgstr "" +msgstr "تکثیر کردن…" #: bottles/frontend/ui/dialog-duplicate.blp:78 #: bottles/frontend/ui/dialog-installer.blp:103 #: bottles/frontend/ui/dialog-upgrade-versioning.blp:112 #: bottles/frontend/views/new.py:177 msgid "This could take a while." -msgstr "" +msgstr "ممکن است کمی طول بکشد." #: bottles/frontend/ui/dialog-duplicate.blp:97 msgid "Bottle Duplicated" -msgstr "" +msgstr "بطری تکثیر شد" #: bottles/frontend/ui/dialog-env-vars.blp:28 msgid "" @@ -1132,16 +1100,15 @@ msgstr "" #: bottles/frontend/ui/dialog-env-vars.blp:31 msgid "Variable Name" -msgstr "" +msgstr "نام متغیّر" #: bottles/frontend/ui/dialog-env-vars.blp:37 -#, fuzzy msgid "Existing Variables" -msgstr "درایو های موجود" +msgstr "متغیّرهای موجود" #: bottles/frontend/ui/dialog-exclusion-patterns.blp:20 msgid "Exclusion Patterns" -msgstr "" +msgstr "الگوهای بیرون گذاشتن" #: bottles/frontend/ui/dialog-exclusion-patterns.blp:28 msgid "" @@ -1154,13 +1121,12 @@ msgid "Pattern" msgstr "الگو" #: bottles/frontend/ui/dialog-exclusion-patterns.blp:37 -#, fuzzy msgid "Existing Patterns" -msgstr "درایو های موجود" +msgstr "الگوهای موجود" #: bottles/frontend/ui/dialog-gamescope.blp:6 msgid "Gamescope Settings" -msgstr "" +msgstr "تنظیمات Gamescope" #: bottles/frontend/ui/dialog-gamescope.blp:30 #: bottles/frontend/ui/dialog-launch-options.blp:32 @@ -1174,9 +1140,8 @@ msgid "Manage how games should be displayed." msgstr "" #: bottles/frontend/ui/dialog-gamescope.blp:44 -#, fuzzy msgid "Game Resolution" -msgstr "رزولوشن بازی" +msgstr "وضوح بازی" #: bottles/frontend/ui/dialog-gamescope.blp:45 msgid "Uses the resolution of the video game as a reference in pixels." @@ -1185,17 +1150,16 @@ msgstr "" #: bottles/frontend/ui/dialog-gamescope.blp:48 #: bottles/frontend/ui/dialog-gamescope.blp:85 msgid "Width" -msgstr "عرض" +msgstr "پهنا" #: bottles/frontend/ui/dialog-gamescope.blp:64 #: bottles/frontend/ui/dialog-gamescope.blp:101 msgid "Height" -msgstr "ارتفاع" +msgstr "بلندا" #: bottles/frontend/ui/dialog-gamescope.blp:81 -#, fuzzy msgid "Window Resolution" -msgstr "نسخه ویندوز" +msgstr "وضوح پنجره" #: bottles/frontend/ui/dialog-gamescope.blp:82 msgid "" @@ -1216,18 +1180,16 @@ msgid "Frame Rate Limit When Unfocused" msgstr "" #: bottles/frontend/ui/dialog-gamescope.blp:153 -#, fuzzy msgid "Integer Scaling" -msgstr "پیکربندی" +msgstr "مقیاس بندی صحیح" #: bottles/frontend/ui/dialog-gamescope.blp:162 -#, fuzzy msgid "Window Type" -msgstr "نوع پنجره" +msgstr "گونهٔ پنجره" #: bottles/frontend/ui/dialog-gamescope.blp:166 msgid "Borderless" -msgstr "" +msgstr "بی‌حاشیه" #: bottles/frontend/ui/dialog-gamescope.blp:172 msgid "Fullscreen" @@ -1239,7 +1201,7 @@ msgstr "" #: bottles/frontend/ui/dialog-installer.blp:45 msgid "Start Installation" -msgstr "" +msgstr "آغاز نصب" #: bottles/frontend/ui/dialog-installer.blp:64 msgid "" @@ -1256,9 +1218,8 @@ msgid "Completed!" msgstr "کامل شده!" #: bottles/frontend/ui/dialog-installer.blp:130 -#, fuzzy msgid "Show Programs" -msgstr "برنامه ها" +msgstr "نمایش برنامه‌ها" #: bottles/frontend/ui/dialog-installer.blp:148 msgid "Installation Failed!" @@ -1266,12 +1227,11 @@ msgstr "نصب شکست خورد!" #: bottles/frontend/ui/dialog-installer.blp:149 msgid "Something went wrong." -msgstr "" +msgstr "چیزی اشتباه پیش رفت." #: bottles/frontend/ui/dialog-journal.blp:9 -#, fuzzy msgid "All messages" -msgstr "حذف پیغام" +msgstr "همهٔ پیام‌ها" #: bottles/frontend/ui/dialog-journal.blp:13 msgid "Critical" @@ -1311,11 +1271,11 @@ msgstr "" #: bottles/frontend/ui/dialog-launch-options.blp:43 msgid "Custom Arguments" -msgstr "" +msgstr "آرگومان‌های سفارشی" #: bottles/frontend/ui/dialog-launch-options.blp:46 msgid "Command Arguments" -msgstr "" +msgstr "آرگومان‌های فرمان" #: bottles/frontend/ui/dialog-launch-options.blp:47 #, c-format @@ -1324,7 +1284,7 @@ msgstr "" #: bottles/frontend/ui/dialog-launch-options.blp:52 msgid "Post-run Script" -msgstr "" +msgstr "کدنوشتهٔ پس از اجرا" #. endregion #: bottles/frontend/ui/dialog-launch-options.blp:53 @@ -1333,9 +1293,8 @@ msgid "Choose a script which should be executed after run." msgstr "" #: bottles/frontend/ui/dialog-launch-options.blp:70 -#, fuzzy msgid "Choose a Script" -msgstr "انتخاب مسیر" +msgstr "گزینش کدنوشته" #: bottles/frontend/ui/dialog-launch-options.blp:84 #: bottles/frontend/windows/launchoptions.py:55 @@ -1344,9 +1303,8 @@ msgstr "" #: bottles/frontend/ui/dialog-launch-options.blp:101 #: bottles/frontend/ui/drive-entry.blp:22 -#, fuzzy msgid "Choose a Directory" -msgstr "انتخاب مسیر" +msgstr "گزینش شاخه" #: bottles/frontend/ui/dialog-launch-options.blp:114 msgid "These settings will override the default settings for this executable." @@ -1354,24 +1312,23 @@ msgstr "" #: bottles/frontend/ui/dialog-launch-options.blp:115 msgid "Preferences Overrides" -msgstr "" +msgstr "پایمالی‌های ترجیحات" #: bottles/frontend/ui/dialog-launch-options.blp:119 -#, fuzzy msgid "Reset to Bottle's Defaults" -msgstr "بطری‌ها" +msgstr "بازنشانی به پیش‌گزیدهٔ بطری‌ها" #: bottles/frontend/ui/dialog-launch-options.blp:165 msgid "Virtual Desktop" -msgstr "" +msgstr "میزکار مجازی" #: bottles/frontend/ui/dialog-proton-alert.blp:4 msgid "Proton Disclaimer" -msgstr "" +msgstr "رفع مسئولیت پروتون" #: bottles/frontend/ui/dialog-proton-alert.blp:21 msgid "Use Proton" -msgstr "" +msgstr "استفاده از پروتون" #: bottles/frontend/ui/dialog-proton-alert.blp:35 msgid "" @@ -1401,9 +1358,8 @@ msgid "Choose a new name for the selected program." msgstr "" #: bottles/frontend/ui/dialog-rename.blp:33 -#, fuzzy msgid "New Name" -msgstr "نام" +msgstr "نام جدید" #: bottles/frontend/ui/dialog-run-args.blp:13 msgid "Run With Arguments" @@ -1424,23 +1380,20 @@ msgid "e.g.: -opengl -SkipBuildPatchPrereq" msgstr "" #: bottles/frontend/ui/dialog-sandbox.blp:7 -#, fuzzy msgid "Sandbox Settings" -msgstr "تنظیمات نمایش" +msgstr "تنظیمات گودال ماسه" #: bottles/frontend/ui/dialog-sandbox.blp:25 msgid "Share Network" -msgstr "" +msgstr "هم‌رسانی شبکه" #: bottles/frontend/ui/dialog-sandbox.blp:34 -#, fuzzy msgid "Share Sound" -msgstr "حذف کننده" +msgstr "هم‌رسانی صدا" #: bottles/frontend/ui/dialog-upgrade-versioning.blp:16 -#, fuzzy msgid "Upgrade Needed" -msgstr "ارتقا" +msgstr "نیازمند ارتقا" #: bottles/frontend/ui/dialog-upgrade-versioning.blp:38 #: bottles/frontend/ui/onboard.blp:81 @@ -1449,7 +1402,7 @@ msgstr "ادامه" #: bottles/frontend/ui/dialog-upgrade-versioning.blp:47 msgid "Launch upgrade" -msgstr "" +msgstr "اجرای ارتقا" #: bottles/frontend/ui/dialog-upgrade-versioning.blp:66 msgid "New Versioning System" @@ -1476,7 +1429,7 @@ msgstr "" #: bottles/frontend/ui/dialog-upgrade-versioning.blp:103 msgid "Re-initializing Repository…" -msgstr "" +msgstr "مقداردهی نخستین دوبارهٔ مخزن…" #: bottles/frontend/ui/dialog-upgrade-versioning.blp:133 msgid "Done! Please restart Bottles." @@ -1492,9 +1445,8 @@ msgid "Default" msgstr "پیش‌گزیده" #: bottles/frontend/ui/dialog-vkbasalt.blp:48 -#, fuzzy msgid "Default Settings" -msgstr "تنظیمات نمایش" +msgstr "تنظیمات پیش‌گزیده" #: bottles/frontend/ui/dialog-vkbasalt.blp:57 msgid "Effects are applied according to the list order." @@ -1541,9 +1493,8 @@ msgid "Fast Approximate Anti-Aliasing" msgstr "" #: bottles/frontend/ui/dialog-vkbasalt.blp:163 -#, fuzzy msgid "Subpixel Quality" -msgstr "کیفیت فوق العاده" +msgstr "کیفیت زیرپیکسل" #: bottles/frontend/ui/dialog-vkbasalt.blp:191 msgid "Quality Edge Threshold" @@ -1559,7 +1510,7 @@ msgstr "" #: bottles/frontend/ui/dialog-vkbasalt.blp:252 msgid "Edge Detection" -msgstr "" +msgstr "تشخیص لبه" #: bottles/frontend/ui/dialog-vkbasalt.blp:267 msgid "Luma" @@ -1677,7 +1628,7 @@ msgstr "برداشتن" #: bottles/frontend/ui/drive-entry.blp:5 msgid "/point/to/path" -msgstr "" +msgstr "/point/to/path" #: bottles/frontend/ui/env-var-entry.blp:4 #: bottles/frontend/ui/exclusion-pattern-entry.blp:4 @@ -1710,9 +1661,8 @@ msgid "Search again for prefixes" msgstr "" #: bottles/frontend/ui/importer.blp:38 -#, fuzzy msgid "No Prefixes Found" -msgstr "برنامه ها" +msgstr "هیج پیشوندی پیدا نشد" #: bottles/frontend/ui/importer.blp:39 msgid "" @@ -1722,25 +1672,23 @@ msgstr "" #: bottles/frontend/ui/importer.blp:74 msgid "Full Archive" -msgstr "" +msgstr "بایگانی کامل" #: bottles/frontend/ui/installer-entry.blp:16 msgid "Show Manifest…" -msgstr "" +msgstr "نمایش بیانیه…" #: bottles/frontend/ui/installer-entry.blp:20 msgid "Read Review…" -msgstr "" +msgstr "خواندن بازبینی…" #: bottles/frontend/ui/installer-entry.blp:34 -#, fuzzy msgid "Installer name" -msgstr "حذف کننده" +msgstr "نام نصب کننده" #: bottles/frontend/ui/installer-entry.blp:35 -#, fuzzy msgid "Installer description" -msgstr "حذف کننده" +msgstr "شرح نصب کننده" #: bottles/frontend/ui/installer-entry.blp:42 msgid "Unknown" @@ -1748,16 +1696,15 @@ msgstr "ناشناخته" #: bottles/frontend/ui/installer-entry.blp:51 msgid "Install this Program" -msgstr "" +msgstr "نصب این برنامه" #: bottles/frontend/ui/installer-entry.blp:69 -#, fuzzy msgid "Program Menu" -msgstr "برنامه ها" +msgstr "فهرست برنامه‌ها" #: bottles/frontend/ui/library-entry.blp:36 msgid "No Thumbnail" -msgstr "" +msgstr "بدون بندانگشتی" #: bottles/frontend/ui/library-entry.blp:57 msgid "Launch" @@ -1769,14 +1716,12 @@ msgid "Launch with Steam" msgstr "اجرا با استیم" #: bottles/frontend/ui/library-entry.blp:108 -#, fuzzy msgid "Item name" -msgstr "تغییر نام" +msgstr "نام مورد" #: bottles/frontend/ui/library-entry.blp:132 -#, fuzzy msgid "Remove from Library" -msgstr "حذف از برنامه ها" +msgstr "برداشتن از کتابخانه" #: bottles/frontend/ui/library-entry.blp:143 msgid "Stop" @@ -1815,11 +1760,11 @@ msgstr "" #: bottles/frontend/ui/list.blp:12 msgid "Search your bottles…" -msgstr "" +msgstr "جست‌وجوی بطری‌هایتان…" #: bottles/frontend/ui/list.blp:28 msgid "Steam Proton" -msgstr "" +msgstr "پروتون استیم" # Translators: Bottles is a generic noun here, referring to wine prefixes and is to be translated #: bottles/frontend/ui/list.blp:42 bottles/frontend/windows/main_window.py:191 @@ -1833,7 +1778,7 @@ msgstr "ایجاد بطری جدید…" #: bottles/frontend/ui/list.blp:63 msgid "No Results Found" -msgstr "" +msgstr "هیج نتیجه‌ای پیدا نشد" #: bottles/frontend/ui/list.blp:64 msgid "Try a different search." @@ -1841,7 +1786,7 @@ msgstr "" #: bottles/frontend/ui/loading.blp:13 msgid "Starting up…" -msgstr "" +msgstr "آغاز به کار…" #: bottles/frontend/ui/local-resource-entry.blp:4 msgid "This resource is missing." @@ -1856,9 +1801,8 @@ msgid "C_reate" msgstr "_ایجاد" #: bottles/frontend/ui/new.blp:53 -#, fuzzy msgid "Bottle Name" -msgstr "بطری‌ها" +msgstr "نام بطری" #: bottles/frontend/ui/new.blp:75 msgid "_Application" @@ -1866,7 +1810,7 @@ msgstr "_برنامه" #: bottles/frontend/ui/new.blp:88 msgid "_Gaming" -msgstr "_بازی کردن" +msgstr "با_زی" #: bottles/frontend/ui/new.blp:101 msgid "C_ustom" @@ -1877,9 +1821,8 @@ msgid "Custom" msgstr "سفارشی" #: bottles/frontend/ui/new.blp:118 -#, fuzzy msgid "Share User Directory" -msgstr "انتخاب مسیر" +msgstr "هم‌رسانی شاخهٔ کاربر" #: bottles/frontend/ui/new.blp:119 msgid "" @@ -1901,9 +1844,8 @@ msgid "Import a custom configuration." msgstr "درون‌ریزی پیکربندی سفارشی." #: bottles/frontend/ui/new.blp:176 -#, fuzzy msgid "Bottle Directory" -msgstr "انتخاب مسیر" +msgstr "شاخهٔ بطری" #: bottles/frontend/ui/new.blp:177 msgid "Directory that will contain the data of this bottle." @@ -1924,7 +1866,7 @@ msgstr "پیشین" # Translators: Bottles is a proper noun referring to the app #: bottles/frontend/ui/onboard.blp:59 msgid "Welcome to Bottles" -msgstr "" +msgstr "به بطری‌ها خوش آمدید" #: bottles/frontend/ui/onboard.blp:60 msgid "Run Windows Software on Linux." @@ -1932,9 +1874,8 @@ msgstr "اجرای نرم‌افزارهای ویندوزی روی گنو/لین # Translators: Bottles is a generic noun here, referring to wine prefixes and is to be translated #: bottles/frontend/ui/onboard.blp:65 -#, fuzzy msgid "Windows in Bottles" -msgstr "نوع پنجره" +msgstr "ویندوز در بطری‌ها" #: bottles/frontend/ui/onboard.blp:66 msgid "" @@ -1944,7 +1885,7 @@ msgstr "" #: bottles/frontend/ui/onboard.blp:72 msgid "Almost Done" -msgstr "" +msgstr "تقریباً تمام" #: bottles/frontend/ui/onboard.blp:73 msgid "We need a few more minutes to set everything up…" @@ -1952,7 +1893,7 @@ msgstr "" #: bottles/frontend/ui/onboard.blp:105 msgid "All Ready!" -msgstr "" +msgstr "همه چیز آماده است!" #: bottles/frontend/ui/onboard.blp:114 msgid "Please Finish the setup first" @@ -1981,9 +1922,8 @@ msgid "Appearance" msgstr "ظاهر" #: bottles/frontend/ui/preferences.blp:17 -#, fuzzy msgid "Dark Mode" -msgstr "قالب تاریک" +msgstr "حالت تاریک" #: bottles/frontend/ui/preferences.blp:18 msgid "Whether Bottles should use the dark color scheme." @@ -2007,9 +1947,8 @@ msgid "Show notifications for downloads and installs." msgstr "" #: bottles/frontend/ui/preferences.blp:52 -#, fuzzy msgid "Temp Files" -msgstr "پاکسازی فایل‌های موقت" +msgstr "پرونده‌های موقّتی" #: bottles/frontend/ui/preferences.blp:53 msgid "Clean temp files when Bottles launches?" @@ -2064,9 +2003,8 @@ msgid "Advanced" msgstr "پیشرفته" #: bottles/frontend/ui/preferences.blp:131 -#, fuzzy msgid "Bottles Directory" -msgstr "انتخاب مسیر" +msgstr "شاخهٔ بطری‌ها" #: bottles/frontend/ui/preferences.blp:132 msgid "Directory that contains the data of your Bottles." @@ -2098,7 +2036,7 @@ msgstr "" #: bottles/frontend/ui/preferences.blp:270 msgid "DXVK-NVAPI" -msgstr "" +msgstr "DXVK-NVAPI" #: bottles/frontend/ui/preferences.blp:283 msgid "Core" @@ -2110,7 +2048,7 @@ msgstr "زمان اجرا" #: bottles/frontend/ui/preferences.blp:291 msgid "WineBridge" -msgstr "" +msgstr "پل واین" #: bottles/frontend/ui/preferences.blp:297 #: data/com.usebottles.bottles.gschema.xml:66 @@ -2132,65 +2070,57 @@ msgid "In early development." msgstr "" #: bottles/frontend/ui/program-entry.blp:19 -#, fuzzy msgid "Launch with Terminal" -msgstr "اجرا با ترمینال" +msgstr "اجرا در پایانه" #: bottles/frontend/ui/program-entry.blp:25 -#, fuzzy msgid "Browse Path" -msgstr "مرور فایل ها" +msgstr "مرور مسیر" #: bottles/frontend/ui/program-entry.blp:39 msgid "Change Launch Options…" msgstr "تغییر گزینه‌های اجرا…" #: bottles/frontend/ui/program-entry.blp:43 -#, fuzzy msgid "Add to Library" -msgstr "افزودن به کتابخانه من" +msgstr "افزودن به کتابخانه" #: bottles/frontend/ui/program-entry.blp:47 msgid "Add Desktop Entry" -msgstr "" +msgstr "افزودن مدخل میزکار" #: bottles/frontend/ui/program-entry.blp:51 msgid "Add to Steam" -msgstr "" +msgstr "افزودن به استیم" #: bottles/frontend/ui/program-entry.blp:55 msgid "Rename…" msgstr "تغییر نام…" #: bottles/frontend/ui/program-entry.blp:62 -#, fuzzy msgid "Hide Program" -msgstr "برنامه ها" +msgstr "نهفتن برنامه" #: bottles/frontend/ui/program-entry.blp:66 -#, fuzzy msgid "Show Program" -msgstr "برنامه ها" +msgstr "نمایش برنامه" #: bottles/frontend/ui/program-entry.blp:70 -#, fuzzy msgid "Remove from List" -msgstr "حذف از برنامه ها" +msgstr "برداشتن از سیاهه" #: bottles/frontend/ui/program-entry.blp:83 -#, fuzzy msgid "Program name" -msgstr "برنامه ها" +msgstr "نام برنامه" #. Translators: id as identification #: bottles/frontend/ui/state-entry.blp:8 -#, fuzzy msgid "State id" -msgstr "حذف کننده" +msgstr "شناسهٔ وضعیت" #: bottles/frontend/ui/state-entry.blp:9 msgid "State comment" -msgstr "" +msgstr "نظر وضعیت" #: bottles/frontend/ui/state-entry.blp:16 msgid "Restore this Snapshot" @@ -2202,7 +2132,7 @@ msgstr "حذف پیغام" #: bottles/frontend/ui/window.blp:40 msgid "Main Menu" -msgstr "" +msgstr "فهرست اصلی" #: bottles/frontend/ui/window.blp:54 msgid "" @@ -2227,33 +2157,31 @@ msgstr "دربارهٔ بطری‌ها" #: bottles/frontend/views/bottle_details.py:191 #, python-brace-format msgid "File \"{0}\" is not a .exe or .msi file" -msgstr "" +msgstr "پروندهٔ «{0}» از نوع exe یا msi نیست" #: bottles/frontend/views/bottle_details.py:207 #, python-format msgid "Updated: %s" -msgstr "بروز شده: %s" +msgstr "به‌روز شده: %s" #: bottles/frontend/views/bottle_details.py:267 #, python-brace-format msgid "\"{0}\" added" -msgstr "" +msgstr "«{0}» افزوده شد" #: bottles/frontend/views/bottle_details.py:270 #: bottles/frontend/views/bottle_details.py:398 #: bottles/frontend/views/list.py:128 -#, fuzzy msgid "Select Executable" -msgstr "حذف Bottle" +msgstr "گزینش پروندهٔ اجرایی" #: bottles/frontend/views/bottle_details.py:273 msgid "Add" msgstr "افزودن" #: bottles/frontend/views/bottle_details.py:346 -#, fuzzy msgid "Hide Hidden Programs" -msgstr "نمایش/مخفی سازی برنامه های حذف شده" +msgstr "نهفتن برنامه‌های نهفته" #: bottles/frontend/views/bottle_details.py:383 #: bottles/frontend/widgets/library.py:156 @@ -2321,7 +2249,7 @@ msgstr "_حذف" #: bottles/frontend/views/bottle_details.py:521 msgid "Missing Runner" -msgstr "" +msgstr "اجراگر غایب" #: bottles/frontend/views/bottle_details.py:522 msgid "" @@ -2339,7 +2267,7 @@ msgstr "" #: bottles/frontend/views/bottle_details.py:601 msgid "Force _Stop" -msgstr "" +msgstr "توقّف _اجباری" #: bottles/frontend/views/bottle_preferences.py:195 msgid "This feature is unavailable on your system." @@ -2355,9 +2283,8 @@ msgstr "" #: bottles/frontend/views/bottle_preferences.py:301 #: bottles/frontend/windows/launchoptions.py:241 -#, fuzzy msgid "Select Working Directory" -msgstr "انتخاب مسیر" +msgstr "گزینش شاخهٔ کاری" #: bottles/frontend/views/bottle_preferences.py:423 msgid "Directory that contains the data of \"{}\"." @@ -2377,7 +2304,7 @@ msgstr "" #: bottles/frontend/views/details.py:153 msgid "Installers" -msgstr "" +msgstr "نصب کننده‌ها" #: bottles/frontend/views/details.py:234 msgid "Operations in progress, please wait." @@ -2393,12 +2320,12 @@ msgstr "" #: bottles/frontend/views/importer.py:94 msgid "Import failed" -msgstr "" +msgstr "درون‌ریزی شکست خورد" #: bottles/frontend/views/importer.py:108 #: bottles/frontend/views/importer.py:147 msgid "Importing backup…" -msgstr "" +msgstr "درون ریختن پشتیبان…" #: bottles/frontend/views/importer.py:119 msgid "Select a Backup Archive" @@ -2410,13 +2337,12 @@ msgid "Import" msgstr "درون‌ریزی" #: bottles/frontend/views/importer.py:158 bottles/frontend/views/new.py:136 -#, fuzzy msgid "Select a Configuration File" -msgstr "پیکربندی" +msgstr "گزینش پروندهٔ پیکربندی" #: bottles/frontend/views/list.py:60 bottles/frontend/views/list.py:66 msgid "N/A" -msgstr "" +msgstr "N/A" #. Set tooltip text #: bottles/frontend/views/list.py:91 @@ -2430,9 +2356,8 @@ msgid "Launching \"{0}\" in \"{1}\"…" msgstr "اجرای «{0}» در «{1}»…" #: bottles/frontend/views/list.py:235 -#, fuzzy msgid "Your Bottles" -msgstr "بطری‌ها" +msgstr "بطری‌هایتان" #: bottles/frontend/views/loading.py:41 #, python-brace-format @@ -2445,18 +2370,16 @@ msgid "Fetched {0} of {1} packages" msgstr "" #: bottles/frontend/views/new.py:157 -#, fuzzy msgid "Select Bottle Directory" -msgstr "انتخاب مسیر" +msgstr "گزینش شاخهٔ بطری" #: bottles/frontend/views/new.py:176 msgid "Creating Bottle…" msgstr "ایجاد کردن بطری…" #: bottles/frontend/views/new.py:221 -#, fuzzy msgid "Unable to Create Bottle" -msgstr "بطری‌ها" +msgstr "ناتواتن در ایجاد بطری" #: bottles/frontend/views/new.py:225 msgid "Bottle failed to create with one or more errors." @@ -2464,9 +2387,8 @@ msgstr "" #. Show success #: bottles/frontend/views/new.py:232 -#, fuzzy msgid "Bottle Created" -msgstr "بطری‌ها" +msgstr "بطری ایجاد شد" #: bottles/frontend/views/new.py:233 #, python-brace-format @@ -2478,13 +2400,12 @@ msgid "Steam was not found or Bottles does not have enough permissions." msgstr "" #: bottles/frontend/views/preferences.py:176 -#, fuzzy msgid "Select Bottles Path" -msgstr "حذف Bottle" +msgstr "گزینش مسیر بطری‌ها" #: bottles/frontend/views/preferences.py:198 msgid "Relaunch Bottles?" -msgstr "احرای دوبارهٔ بطری‌ها؟" +msgstr "اجرای دوبارهٔ بطری‌ها؟" #: bottles/frontend/views/preferences.py:199 msgid "" @@ -2553,7 +2474,7 @@ msgstr "نصب «{0}» شکست خورد" #: bottles/frontend/widgets/importer.py:68 #, python-brace-format msgid "\"{0}\" imported" -msgstr "" +msgstr "«{0}»‌ درون‌ریخته شده" #: bottles/frontend/widgets/installer.py:49 msgid "" @@ -2615,7 +2536,7 @@ msgstr "" #: bottles/frontend/widgets/program.py:297 #, python-brace-format msgid "Desktop Entry created for \"{0}\"" -msgstr "" +msgstr "مدخل میزکار برای «{0}» ساخته شد" #: bottles/frontend/widgets/program.py:313 #, python-brace-format @@ -2638,23 +2559,20 @@ msgid "" msgstr "" #: bottles/frontend/windows/display.py:102 -#, fuzzy msgid "Updating display settings, please wait…" -msgstr "در حال بروزرسانی نسخه ویندوز، لطفا صبر کنید…" +msgstr "به‌روز کردن تنظیمات نمایش. لطفاُ شکیبا باشید…" #: bottles/frontend/windows/display.py:114 -#, fuzzy msgid "Display settings updated" -msgstr "تنظیمات نمایش" +msgstr "تنظیمات نمایش به‌روز شد" #: bottles/frontend/windows/dlloverrides.py:136 msgid "No overrides found." msgstr "" #: bottles/frontend/windows/drives.py:71 -#, fuzzy msgid "Select Drive Path" -msgstr "حذف Bottle" +msgstr "گزینش مسیر گرداننده" #: bottles/frontend/windows/envvars.py:131 msgid "No environment variables defined." @@ -2675,9 +2593,8 @@ msgid "Copy to clipboard" msgstr "" #: bottles/frontend/windows/installer.py:62 -#, fuzzy msgid "Select Resource File" -msgstr "حذف Bottle" +msgstr "گزینش پروندهٔ منبع" #: bottles/frontend/windows/installer.py:109 msgid "Installing Windows dependencies…" @@ -2723,9 +2640,8 @@ msgid "This setting is different from the bottle's default." msgstr "" #: bottles/frontend/windows/launchoptions.py:215 -#, fuzzy msgid "Select Script" -msgstr "حذف Bottle" +msgstr "گزینش کدنوشته" #: bottles/frontend/windows/main_window.py:220 msgid "Custom Bottles Path not Found" @@ -2742,9 +2658,8 @@ msgstr "بطری‌ها" #: data/com.usebottles.bottles.desktop.in.in:4 #: data/com.usebottles.bottles.metainfo.xml.in:8 -#, fuzzy msgid "Run Windows Software" -msgstr "اجرای نرم‌افزار ویندوز" +msgstr "اجرای نرم‌افزارهای ویندوزی" #: data/com.usebottles.bottles.desktop.in.in:13 msgid "wine;windows;" @@ -2756,15 +2671,15 @@ msgstr "مهاجرت فلت‌پک" #: data/com.usebottles.bottles.gschema.xml:7 msgid "Toggle the Flatpak migration dialog." -msgstr "" +msgstr "تغییر وضعیت گفت‌وگوی مهاحرت فلت‌پک." #: data/com.usebottles.bottles.gschema.xml:11 msgid "Dark theme" -msgstr "قالب تاریک" +msgstr "زمینهٔ تاریک" #: data/com.usebottles.bottles.gschema.xml:12 msgid "Force the use of dark theme." -msgstr "اجبار به استفاده از قالب تاریک." +msgstr "اجبار به استفاده از زمینهٔ تاریک." #: data/com.usebottles.bottles.gschema.xml:16 msgid "Toggle update date in list" @@ -2857,9 +2772,8 @@ msgid "Toggle Steam Proton prefixes support." msgstr "" #: data/com.usebottles.bottles.gschema.xml:76 -#, fuzzy msgid "Experiments:sandbox" -msgstr "آزمایشات:steam" +msgstr "آزمایش‌ها:گودال ماسه" #: data/com.usebottles.bottles.gschema.xml:77 msgid "Toggle experimental Sandbox per bottle." @@ -2883,7 +2797,7 @@ msgstr "" #: data/com.usebottles.bottles.metainfo.xml.in:11 msgid "Run Windows software on Linux with Bottles!" -msgstr "اجرای نرم‌افزارهای وندوز روی لینوکس با بطری‌ها!" +msgstr "اجرای نرم‌افزارهای ویندوزی روی گنو/لینوکس با بطری‌ها!" #: data/com.usebottles.bottles.metainfo.xml.in:12 msgid "Bottle software and enjoy at your leisure!" @@ -2971,13 +2885,12 @@ msgid "Import Wine prefixes from other managers" msgstr "وارد کردن پیشوندهای Wine از دیگر مدیران" #: data/com.usebottles.bottles.metainfo.xml.in:34 -#, fuzzy msgid "Bottles versioning" -msgstr "نسخه سازی بطری‌ها ( اختیاری )" +msgstr "نگارش بطری‌ها" #: data/com.usebottles.bottles.metainfo.xml.in:35 msgid "... and much more that you can find by installing Bottles!" -msgstr "... و بسیاری دیگر که با نصب بطری‌ها می‌توانید پیدا کنید" +msgstr "... و ویژگی‌های دیگری که می‌توان با نصب بطری‌ها یافت!" #: data/com.usebottles.bottles.metainfo.xml.in:84 msgid "Update metadata information" @@ -3000,9 +2913,8 @@ msgid "Fixed Patool double extraction failing" msgstr "" #: data/com.usebottles.bottles.metainfo.xml.in:101 -#, fuzzy msgid "Correct version" -msgstr "نمایش نسخه" +msgstr "نگارش درست" #: data/com.usebottles.bottles.metainfo.xml.in:106 msgid "Fix crash when creating a bottle" @@ -3055,9 +2967,8 @@ msgid "Fix error when downloading if Bottles isn't run from terminal" msgstr "" #: data/com.usebottles.bottles.metainfo.xml.in:137 -#, fuzzy msgid "Correct version date" -msgstr "تاریخ ایجاد" +msgstr "تاریخ نگارش درست" #: data/com.usebottles.bottles.metainfo.xml.in:138 msgid "Hide NVIDIA-related critical errors on non NVIDIA systems" diff --git a/po/fi.po b/po/fi.po index f96880780ac..e0c7246904d 100644 --- a/po/fi.po +++ b/po/fi.po @@ -8,8 +8,8 @@ msgstr "" "Project-Id-Version: bottles\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2023-03-27 13:50+0530\n" -"PO-Revision-Date: 2024-05-17 09:01+0000\n" -"Last-Translator: Ilkka Myller \n" +"PO-Revision-Date: 2025-01-15 00:23+0000\n" +"Last-Translator: Ricky Tigg \n" "Language-Team: Finnish \n" "Language: fi\n" @@ -17,7 +17,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 5.6-dev\n" +"X-Generator: Weblate 5.10-dev\n" #: bottles/backend/managers/backup.py:48 bottles/backend/managers/backup.py:95 msgid "No path specified" @@ -1358,9 +1358,9 @@ msgid "Command Arguments" msgstr "Komennon argumentit" #: bottles/frontend/ui/dialog-launch-options.blp:47 -#, fuzzy, c-format +#, c-format msgid "e.g.: VAR=value %command% -example1 -example2 -example3=hello" -msgstr "esim .: -esimerkki1 -esimerkki2 -esimerkki3=hei" +msgstr "esim.: VAR=arvo %command% -esimerkki1 -esimerkki2 -esimerkki3=hei" #: bottles/frontend/ui/dialog-launch-options.blp:52 msgid "Post-run Script" @@ -1770,14 +1770,12 @@ msgid "No Prefixes Found" msgstr "Etuliitteitä ei löytynyt" #: bottles/frontend/ui/importer.blp:39 -#, fuzzy msgid "" "No external prefixes were found. Does Bottles have access to them?\n" "Use the icon on the top to import a bottle from a backup." msgstr "" -"Etuliitteitä ei löytynyt Lutriksesta, PlayOnLinuxista jne.\n" -" Napsauta yllä olevaa kuvaketta " -"tuodaksesi pullon varmuuskopiosta" +"Ulkoisia etuliitteitä ei löytynyt. Onko Bottlesilla pääsy niihin?\n" +"Käytä yläreunassa olevaa kuvaketta tuodaksesi pullon varmuuskopiosta." #: bottles/frontend/ui/importer.blp:74 msgid "Full Archive" @@ -2484,9 +2482,9 @@ msgid "Run executable in \"{self.config.Name}\"" msgstr "Käynnistetään \"{self.config.Name}\"" #: bottles/frontend/views/list.py:118 -#, fuzzy, python-brace-format +#, python-brace-format msgid "Launching \"{0}\" in \"{1}\"…" -msgstr "Käynnistetään \"{0}\"…" +msgstr "Käynnistetään \"{0}\" \"{1}\":ssa…" #: bottles/frontend/views/list.py:235 msgid "Your Bottles" diff --git a/po/ga.po b/po/ga.po new file mode 100644 index 00000000000..05f3321708d --- /dev/null +++ b/po/ga.po @@ -0,0 +1,3231 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the bottles package. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: bottles\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2023-09-27 10:57+0530\n" +"PO-Revision-Date: 2024-10-28 10:01+0000\n" +"Last-Translator: Aindriú Mac Giolla Eoin \n" +"Language-Team: Irish \n" +"Language: ga\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=5; plural=n==1 ? 0 : n==2 ? 1 : (n>2 && n<7) ? 2 :(" +"n>6 && n<11) ? 3 : 4;\n" +"X-Generator: Weblate 5.8.2-dev\n" + +#: bottles/backend/managers/backup.py:48 bottles/backend/managers/backup.py:95 +msgid "No path specified" +msgstr "Níl aon chosán sonraithe" + +#: bottles/backend/managers/backup.py:56 +#, python-brace-format +msgid "Backup {0}" +msgstr "Cúltaca {0}" + +#: bottles/backend/managers/backup.py:103 +#, python-brace-format +msgid "Importing backup: {0}" +msgstr "Cúltaca a iompórtáil: {0}" + +#: bottles/backend/managers/manager.py:1076 +#: bottles/backend/managers/manager.py:1396 +#: bottles/backend/managers/manager.py:1397 +#, python-format +msgid "Failed to install dependency: %s" +msgstr "Theip ar spleáchas a shuiteáil: %s" + +#: bottles/backend/managers/manager.py:1115 +msgid "Fail to install components, tried 3 times." +msgstr "Teip ar chomhpháirteanna a shuiteáil, triail as 3 huaire." + +#: bottles/backend/managers/manager.py:1126 +msgid "Missing essential components. Installing…" +msgstr "Comhpháirteanna riachtanacha ar iarraidh. Ag suiteáil…" + +#: bottles/backend/managers/manager.py:1203 +msgid "Failed to create bottle directory." +msgstr "Theip ar eolaire buidéal a chruthú." + +#: bottles/backend/managers/manager.py:1215 +msgid "Failed to create placeholder directory/file." +msgstr "Theip ar eolair/comhad sealbhóra áite a chruthú." + +#: bottles/backend/managers/manager.py:1220 +msgid "Generating bottle configuration…" +msgstr "Cumraíocht an bhuidéil á ghiniúint…" + +#: bottles/backend/managers/manager.py:1243 +msgid "Template found, applying…" +msgstr "Aimsíodh an teimpléad, á chur i bhfeidhm…" + +#. execute wineboot on the bottle path +#: bottles/backend/managers/manager.py:1255 +msgid "The Wine config is being updated…" +msgstr "Tá an cumraíocht Fíon á nuashonrú…" + +#: bottles/backend/managers/manager.py:1257 +msgid "Wine config updated!" +msgstr "Cumraíocht fíona nuashonraithe!" + +#: bottles/backend/managers/manager.py:1265 +msgid "Running as Flatpak, sandboxing userdir…" +msgstr "Ag rith mar Flatpak, úsáideoir bosca gainimh…" + +#: bottles/backend/managers/manager.py:1267 +msgid "Sandboxing userdir…" +msgstr "Úsáideoir bosca gainimh…" + +#: bottles/backend/managers/manager.py:1308 +msgid "Setting Windows version…" +msgstr "Leagan Windows á shocrú…" + +#: bottles/backend/managers/manager.py:1318 +msgid "Apply CMD default settings…" +msgstr "Cuir socruithe réamhshocraithe CMD i bhfeidhm…" + +#: bottles/backend/managers/manager.py:1326 +msgid "Optimizing environment…" +msgstr "Timpeallacht á bharrfheabhsú…" + +#: bottles/backend/managers/manager.py:1337 +#, python-brace-format +msgid "Applying environment: {0}…" +msgstr "Timpeallacht á chur i bhfeidhm: {0}…" + +#: bottles/backend/managers/manager.py:1347 +msgid "(!) Using a custom environment recipe…" +msgstr "(!) Ag baint úsáide as oideas timpeallachta saincheaptha…" + +#: bottles/backend/managers/manager.py:1350 +msgid "(!) Recipe not not found or not valid…" +msgstr "(!) Níor aimsíodh an t-oideas nó níl sé bailí…" + +#: bottles/backend/managers/manager.py:1367 +msgid "Installing DXVK…" +msgstr "DXVK á shuiteáil…" + +#: bottles/backend/managers/manager.py:1375 +msgid "Installing VKD3D…" +msgstr "VKD3D á shuiteáil…" + +#: bottles/backend/managers/manager.py:1384 +msgid "Installing DXVK-NVAPI…" +msgstr "DXVK-NVAPI á shuiteáil…" + +#: bottles/backend/managers/manager.py:1393 +#, python-format +msgid "Installing dependency: %s …" +msgstr "Spleáchas á shuiteáil: %s …" + +#: bottles/backend/managers/manager.py:1407 +msgid "Creating versioning state 0…" +msgstr "Ag cruthú staid leagan 0…" + +#: bottles/backend/managers/manager.py:1415 +msgid "Finalizing…" +msgstr "Ag críochnú…" + +#: bottles/backend/managers/manager.py:1426 +msgid "Caching template…" +msgstr "Teimpléad Taisce…" + +#: bottles/backend/managers/versioning.py:83 +msgid "Committing state …" +msgstr "Stát geallta…" + +#: bottles/backend/managers/versioning.py:90 +msgid "Nothing to commit" +msgstr "Níl aon rud le tiomantas" + +#: bottles/backend/managers/versioning.py:96 +#, python-brace-format +msgid "New state [{0}] created successfully!" +msgstr "Cruthaíodh stát nua [{0}] go rathúil!" + +#: bottles/backend/managers/versioning.py:123 +msgid "States list retrieved successfully!" +msgstr "Liosta stáit a aisghabháil go rathúil!" + +#: bottles/backend/managers/versioning.py:153 +#, python-brace-format +msgid "State {0} restored successfully!" +msgstr "Athchóirigh an stát {0} go rathúil!" + +#: bottles/backend/managers/versioning.py:155 +msgid "Restoring state {} …" +msgstr "Staid á athchóiriú {}…" + +#: bottles/backend/managers/versioning.py:162 +msgid "State not found" +msgstr "Níor aimsíodh stát" + +#: bottles/backend/managers/versioning.py:168 +msgid "State {} is already the active state" +msgstr "Is é an stát {} an stát gníomhach cheana féin" + +#: bottles/frontend/main.py:111 +msgid "Show version" +msgstr "Taispeáin leagan" + +#: bottles/frontend/main.py:119 +msgid "Executable path" +msgstr "Conair infheidhmithe" + +#: bottles/frontend/main.py:127 +msgid "lnk path" +msgstr "cosán lnk" + +#: bottles/frontend/main.py:135 bottles/frontend/ui/library-entry.blp:118 +#: bottles/frontend/ui/list-entry.blp:5 +msgid "Bottle name" +msgstr "Ainm buidéal" + +#: bottles/frontend/main.py:143 +msgid "Pass arguments" +msgstr "Argóintí a rith" + +#: bottles/frontend/main.py:202 +msgid "Invalid URI (syntax: bottles:run//)" +msgstr "URI neamhbhailí (comhréir: bottles:run//)" + +#: bottles/frontend/main.py:242 +msgid "[Quit] request received." +msgstr "[Stad] iarratas a fuarthas." + +#: bottles/frontend/main.py:252 +msgid "[Help] request received." +msgstr "[Cabhair] iarratas a fuarthas." + +#: bottles/frontend/main.py:260 +msgid "[Refresh] request received." +msgstr "[Athnuachan] iarratas a fuarthas." + +#: bottles/frontend/main.py:293 +msgid "Donate" +msgstr "Deontas" + +#: bottles/frontend/main.py:298 +msgid "Third-Party Libraries and Special Thanks" +msgstr "Leabharlanna tríú páirtí agus Go" + +#: bottles/frontend/main.py:324 +msgid "Sponsored and Funded by" +msgstr "Urraithe agus Maoinithe ag" + +#: bottles/frontend/ui/about.blp:5 +msgid "Copyright © 2017 Bottles Developers" +msgstr "Cóipcheart © 2017 Forbróirí Buidéal" + +#: bottles/frontend/ui/about.blp:10 +msgid "Bottles Developers" +msgstr "Forbróirí Buidéil" + +#: bottles/frontend/ui/about.blp:12 +msgid "translator_credits" +msgstr "creidmheasanna_aistritheoir" + +#: bottles/frontend/ui/component-entry.blp:4 +msgid "Component version" +msgstr "Leagan comhpháirteanna" + +#: bottles/frontend/ui/component-entry.blp:12 +#: bottles/frontend/ui/dependency-entry.blp:29 +#: bottles/frontend/ui/program-entry.blp:77 +msgid "Uninstall" +msgstr "Díshuiteáil" + +#: bottles/frontend/ui/component-entry.blp:23 +#: bottles/frontend/ui/importer-entry.blp:13 +msgid "Browse Files" +msgstr "Brabhsáil Comhaid" + +#: bottles/frontend/ui/component-entry.blp:34 +msgid "" +"The installation failed. This may be due to a repository error, partial " +"download or checksum mismatch. Press to try again." +msgstr "" +"Theip ar an suiteáil. D'fhéadfadh sé seo a bheith mar gheall ar earráid " +"stórais, íoslódáil pháirteach nó mímheaitseáil seicsum. Brúigh chun triail a " +"bhaint as arís." + +#: bottles/frontend/ui/component-entry.blp:45 +msgid "Download & Install" +msgstr "Íoslódáil & Suiteáil" + +#: bottles/frontend/ui/component-entry.blp:58 +msgid "0%" +msgstr "0%" + +#: bottles/frontend/ui/dependency-entry.blp:16 +msgid "Show Manifest" +msgstr "Taispeáin Manifest" + +#: bottles/frontend/ui/dependency-entry.blp:20 +msgid "License" +msgstr "Ceadúnas" + +#: bottles/frontend/ui/dependency-entry.blp:24 +msgid "Reinstall" +msgstr "Athshuiteáil" + +#: bottles/frontend/ui/dependency-entry.blp:36 +#: bottles/frontend/ui/installer-entry.blp:27 +msgid "Report a Bug…" +msgstr "Tuairiscigh fabht…" + +#: bottles/frontend/ui/dependency-entry.blp:42 +msgid "Dependency name" +msgstr "Ainm spleáchais" + +#: bottles/frontend/ui/dependency-entry.blp:44 +msgid "Dependency description" +msgstr "Tuairisc spleáchais" + +#: bottles/frontend/ui/dependency-entry.blp:51 +msgid "Category" +msgstr "Catagóir" + +#: bottles/frontend/ui/dependency-entry.blp:64 +msgid "Download & Install this Dependency" +msgstr "Íoslódáil & Suiteáil an Spleáchas seo" + +#: bottles/frontend/ui/dependency-entry.blp:79 +msgid "" +"An installation error occurred. Restart Bottles to read the Crash Report or " +"run it via terminal to read the output." +msgstr "" +"Tharla earráid suiteála. Athosaigh Buidéil chun an Tuarascáil Crash a léamh " +"nó é a rith trí chríochfort chun an t-aschur a léamh." + +#: bottles/frontend/ui/dependency-entry.blp:93 +msgid "Dependency Menu" +msgstr "Roghchlár Spleachta" + +#: bottles/frontend/ui/details-bottle.blp:16 +msgid "Troubleshooting" +msgstr "Fabhtcheartú" + +#: bottles/frontend/ui/details-bottle.blp:24 +msgid "Browse Files…" +msgstr "Brabhsáil Comhaid…" + +#: bottles/frontend/ui/details-bottle.blp:28 +msgid "Duplicate Bottle…" +msgstr "Buidéal Dúblach…" + +#: bottles/frontend/ui/details-bottle.blp:32 +#: bottles/frontend/ui/importer.blp:73 +msgid "This is the complete archive of your bottle, including personal files." +msgstr "" +"Is é seo cartlann iomlán do bhuidéal, lena n-áirítear comhaid phearsanta." + +#: bottles/frontend/ui/details-bottle.blp:33 +msgid "Full Backup…" +msgstr "Cúltaca Iomlán…" + +#: bottles/frontend/ui/details-bottle.blp:37 +#: bottles/frontend/ui/importer.blp:68 +msgid "" +"This is just the bottle configuration, it's perfect if you want to create a " +"new one but without personal files." +msgstr "" +"Níl anseo ach cumraíocht an bhuidéil, tá sé foirfe más mian leat ceann nua a " +"chruthú ach gan comhaid phearsanta." + +#: bottles/frontend/ui/details-bottle.blp:38 +msgid "Export Configuration…" +msgstr "Cumraíocht Easpórtála…" + +#: bottles/frontend/ui/details-bottle.blp:45 +#: bottles/frontend/views/bottle_details.py:347 +msgid "Show Hidden Programs" +msgstr "Taispeáin Cláir bhfolach" + +#: bottles/frontend/ui/details-bottle.blp:49 +msgid "Search for new programs" +msgstr "Cuardaigh cláir nua" + +#: bottles/frontend/ui/details-bottle.blp:56 +msgid "Delete Bottle…" +msgstr "Scrios Buidéal…" + +#: bottles/frontend/ui/details-bottle.blp:73 +#: bottles/frontend/ui/details-dependencies.blp:99 +#: bottles/frontend/ui/details-installers.blp:68 +msgid "Secondary Menu" +msgstr "Roghchlár Tánaiste" + +#: bottles/frontend/ui/details-bottle.blp:90 +msgid "Force Stop all Processes" +msgstr "Fórsa Stop Gach Próiseas" + +#: bottles/frontend/ui/details-bottle.blp:94 +msgid "Simulate a Windows system shutdown." +msgstr "Samhail múchadh córas Windows." + +#: bottles/frontend/ui/details-bottle.blp:95 +msgid "Shutdown" +msgstr "Múchadh" + +#: bottles/frontend/ui/details-bottle.blp:99 +msgid "Simulate a Windows system reboot." +msgstr "Samhlaigh atosú córas Windows." + +#: bottles/frontend/ui/details-bottle.blp:100 +msgid "Reboot" +msgstr "Athosaigh" + +#: bottles/frontend/ui/details-bottle.blp:118 +#: bottles/frontend/ui/dialog-launch-options.blp:6 +msgid "Launch Options" +msgstr "Roghanna Seolta" + +#: bottles/frontend/ui/details-bottle.blp:135 +msgid "Run in Terminal" +msgstr "Rith i gCríochfort" + +#: bottles/frontend/ui/details-bottle.blp:148 +msgid "Drop files to execute them" +msgstr "Buail comhaid chun iad a fhorghníomhú" + +#: bottles/frontend/ui/details-bottle.blp:164 +msgid "My bottle" +msgstr "Mo buidéal" + +#: bottles/frontend/ui/details-bottle.blp:177 +msgid "Win64" +msgstr "Win64" + +#: bottles/frontend/ui/details-bottle.blp:189 +#: bottles/frontend/ui/list-entry.blp:12 bottles/frontend/ui/new.blp:71 +msgid "Environment" +msgstr "Comhshaol" + +#: bottles/frontend/ui/details-bottle.blp:201 +#: bottles/frontend/ui/details-preferences.blp:14 +#: bottles/frontend/ui/new.blp:128 +msgid "Runner" +msgstr "Raitheoir" + +#: bottles/frontend/ui/details-bottle.blp:213 +#: bottles/frontend/ui/list-entry.blp:21 +msgid "Versioning enabled for this bottle" +msgstr "Leagan cumasaithe don bhuidéal seo" + +#: bottles/frontend/ui/details-bottle.blp:218 +msgid "Versioning is active for this bottle." +msgstr "Tá leagan gníomhach don bhuidéal seo." + +#: bottles/frontend/ui/details-bottle.blp:227 +#: bottles/frontend/ui/list-entry.blp:31 +msgid "0" +msgstr "0" + +#: bottles/frontend/ui/details-bottle.blp:247 +msgid "Run Executable…" +msgstr "Rith Inrite…" + +#: bottles/frontend/ui/details-bottle.blp:272 +msgid "Programs" +msgstr "Cláir" + +#: bottles/frontend/ui/details-bottle.blp:275 +msgid "" +"Click \"Run Executable…\" to run an executable, \"Add Shortcuts…\" to add an " +"executable to the Programs list, or \"Install Programs…\" to install " +"programs curated by the community." +msgstr "" +"Cliceáil \"Rith Infheidhmithe...\" chun infheidhmithe a reáchtáil, \"Cuir " +"Aicearraí leis...\" chun infheidhmithe a chur le liosta na gCláir, nó " +"\"Suiteáil Cláir...\" chun cláir atá coimeádaithe ag an bpobal a shuiteáil." + +#: bottles/frontend/ui/details-bottle.blp:298 +msgid "Add Shortcuts…" +msgstr "Cuir Aicearraí leis…" + +#: bottles/frontend/ui/details-bottle.blp:325 +msgid "Install Programs…" +msgstr "Suiteáil Cláir…" + +#: bottles/frontend/ui/details-bottle.blp:346 +msgid "Options" +msgstr "Roghanna" + +#: bottles/frontend/ui/details-bottle.blp:350 +#: bottles/frontend/views/details.py:141 +msgid "Settings" +msgstr "Socruithe" + +#: bottles/frontend/ui/details-bottle.blp:351 +msgid "Configure bottle settings." +msgstr "Cumraigh socruithe buidéal." + +#: bottles/frontend/ui/details-bottle.blp:360 +#: bottles/frontend/views/details.py:145 +msgid "Dependencies" +msgstr "Spleithiúlachtaí" + +#: bottles/frontend/ui/details-bottle.blp:361 +msgid "Install dependencies for programs." +msgstr "Suiteáil spleáchais do chláir." + +#: bottles/frontend/ui/details-bottle.blp:370 +#: bottles/frontend/ui/details-preferences.blp:376 +#: bottles/frontend/views/details.py:149 +msgid "Snapshots" +msgstr "Snapshots" + +#: bottles/frontend/ui/details-bottle.blp:371 +msgid "Create and manage bottle states." +msgstr "Stáit buidéal a chruthú agus a bhainistiú." + +#: bottles/frontend/ui/details-bottle.blp:380 +#: bottles/frontend/ui/details-bottle.blp:426 +#: bottles/frontend/views/details.py:157 +msgid "Task Manager" +msgstr "Bainisteoir Tasc" + +#: bottles/frontend/ui/details-bottle.blp:381 +msgid "Manage running programs." +msgstr "Bainistigh cláir reatha." + +#: bottles/frontend/ui/details-bottle.blp:390 +msgid "Tools" +msgstr "Uirlisí" + +#: bottles/frontend/ui/details-bottle.blp:394 +msgid "Command Line" +msgstr "Líne Orduithe" + +#: bottles/frontend/ui/details-bottle.blp:395 +msgid "Run commands inside the Bottle." +msgstr "Rith orduithe taobh istigh den Bhuidéal." + +#: bottles/frontend/ui/details-bottle.blp:404 +msgid "Registry Editor" +msgstr "Eagarthóir Chlárlan" + +#: bottles/frontend/ui/details-bottle.blp:405 +msgid "Edit the internal registry." +msgstr "Athraigh an chlárlann inmheánach." + +#: bottles/frontend/ui/details-bottle.blp:413 +msgid "Legacy Wine Tools" +msgstr "Uirlisí Fíona oidhreachta" + +#: bottles/frontend/ui/details-bottle.blp:417 +msgid "Explorer" +msgstr "Taispeántóir" + +#: bottles/frontend/ui/details-bottle.blp:435 +msgid "Debugger" +msgstr "Dífhabhtaitheoir" + +#: bottles/frontend/ui/details-bottle.blp:444 +#: bottles/frontend/ui/importer.blp:69 bottles/frontend/ui/new.blp:145 +msgid "Configuration" +msgstr "Cumraíocht" + +#: bottles/frontend/ui/details-bottle.blp:453 +msgid "Uninstaller" +msgstr "Díshuiteálaí" + +#: bottles/frontend/ui/details-bottle.blp:462 +msgid "Control Panel" +msgstr "Painéal Rialúcháin" + +#: bottles/frontend/ui/details-dependencies.blp:9 +msgid "Search for dependencies…" +msgstr "Cuardaigh spleáchais…" + +#: bottles/frontend/ui/details-dependencies.blp:22 +#: bottles/frontend/ui/preferences.blp:199 +#: bottles/frontend/ui/preferences.blp:247 +msgid "You're offline :(" +msgstr "Tá tú as líne :(" + +#: bottles/frontend/ui/details-dependencies.blp:25 +msgid "Bottles is running in offline mode, so dependencies are not available." +msgstr "Tá buidéil ag rith i mód as líne, mar sin níl spleáchais ar fáil." + +#: bottles/frontend/ui/details-dependencies.blp:47 +msgid "" +"Dependencies are resources that improve compatibility of Windows software.\n" +"\n" +"Files on this page are provided by third parties under a proprietary " +"license. By installing them, you agree with their respective licensing terms." +msgstr "" +"Is acmhainní iad spleáchais a fheabhsaíonn comhoiriúnacht bogearraí Windows\n" +"\n" +"Soláthraíonn tríú páirtithe comhaid ar an leathanach seo faoi cheadúnas " +"dílseánaigh. Trí iad a shuiteáil, aontaíonn tú lena dtéarmaí ceadúnaithe " +"faoi seach." + +#: bottles/frontend/ui/details-dependencies.blp:76 +msgid "Report a problem or a missing dependency." +msgstr "Tuairiscigh fadhb nó spleáchas atá ar iarraidh." + +#: bottles/frontend/ui/details-dependencies.blp:77 +msgid "Report Missing Dependency" +msgstr "Tuairisc ar Spleáchas" + +#: bottles/frontend/ui/details-dependencies.blp:81 +msgid "Read Documentation." +msgstr "Léigh Doiciméadú." + +#: bottles/frontend/ui/details-dependencies.blp:82 +#: bottles/frontend/ui/details-installers.blp:51 +#: bottles/frontend/ui/details-versioning.blp:37 +msgid "Documentation" +msgstr "Doiciméadú" + +#: bottles/frontend/ui/details-dependencies.blp:92 +#: bottles/frontend/ui/details-installers.blp:61 +#: bottles/frontend/ui/window.blp:46 +msgid "Search" +msgstr "Cuardaigh" + +#: bottles/frontend/ui/details-installers.blp:9 +msgid "Search for Programs…" +msgstr "Cuardaigh Cláir…" + +#: bottles/frontend/ui/details-installers.blp:15 +msgid "" +"Install programs curated by our community.\n" +"\n" +"Files on this page are provided by third parties under a proprietary " +"license. By installing them, you agree with their respective licensing terms." +msgstr "" +"Suiteáil cláir atá curtha ag ár bpobal.\n" +"\n" +"Soláthraíonn tríú páirtithe comhaid ar an leathanach seo faoi cheadúnas " +"dílseánaigh. Trí iad a shuiteáil, aontaíonn tú lena dtéarmaí ceadúnaithe " +"faoi seach." + +#: bottles/frontend/ui/details-installers.blp:29 +msgid "No Installers Found" +msgstr "Níl aon Suiteálaithe aimsithe" + +#: bottles/frontend/ui/details-installers.blp:32 +msgid "" +"The repository is unreachable or no installer is compatible with this bottle." +msgstr "" +"Níl an stór inrochtana nó níl aon suiteálaí comhoiriúnach leis an mbuidéal " +"seo." + +#: bottles/frontend/ui/details-installers.blp:50 +#: bottles/frontend/ui/details-versioning.blp:36 +#: bottles/frontend/ui/preferences.blp:82 +msgid "Read Documentation" +msgstr "Léigh Doiciméadú" + +#: bottles/frontend/ui/details-preferences.blp:6 +#: bottles/frontend/ui/dialog-duplicate.blp:52 bottles/frontend/ui/new.blp:53 +msgid "Name" +msgstr "Ainm" + +#: bottles/frontend/ui/details-preferences.blp:11 +msgid "Components" +msgstr "Comhpháirteanna" + +#: bottles/frontend/ui/details-preferences.blp:15 +#: bottles/frontend/ui/new.blp:129 +msgid "The version of the Wine compatibility layer." +msgstr "An leagan den chiseal comhoiriúnachta Fíon." + +#: bottles/frontend/ui/details-preferences.blp:17 +msgid "Updating Runner and components, please wait…" +msgstr "Runner agus comhpháirteanna á nuashonrú, fan go fóill…" + +#: bottles/frontend/ui/details-preferences.blp:27 +#: bottles/frontend/ui/preferences.blp:274 +msgid "DXVK" +msgstr "DXVK" + +#: bottles/frontend/ui/details-preferences.blp:28 +msgid "Improve Direct3D 9/10/11 compatibility by translating it to Vulkan." +msgstr "Comhoiriúnacht Direct3D 9/10/11 a fheabhsú trína aistriú go Vulkan." + +#: bottles/frontend/ui/details-preferences.blp:30 +msgid "Updating DXVK, please wait…" +msgstr "DXVK á nuashonrú, fan go fóill…" + +#: bottles/frontend/ui/details-preferences.blp:40 +#: bottles/frontend/ui/preferences.blp:278 +msgid "VKD3D" +msgstr "VKD3D" + +#: bottles/frontend/ui/details-preferences.blp:41 +msgid "Improve Direct3D 12 compatibility by translating it to Vulkan." +msgstr "Comhoiriúnacht Direct3D 12 a fheabhsú trína aistriú go Vulkan." + +#: bottles/frontend/ui/details-preferences.blp:43 +msgid "Updating VKD3D, please wait…" +msgstr "VKD3D á nuashonrú, fan go fóill…" + +#: bottles/frontend/ui/details-preferences.blp:54 +msgid "DXVK NVAPI" +msgstr "DXVK APP" + +#: bottles/frontend/ui/details-preferences.blp:58 +#: bottles/frontend/ui/details-preferences.blp:93 +msgid "Updating DXVK-NVAPI, please wait…" +msgstr "DXVK-NVAPI á nuashonrú, fan go fóill…" + +#: bottles/frontend/ui/details-preferences.blp:68 +#: bottles/frontend/ui/preferences.blp:286 +msgid "LatencyFleX" +msgstr "LatencyFleX" + +#: bottles/frontend/ui/details-preferences.blp:69 +msgid "Increase responsiveness. Can be detected by some anti-cheat software." +msgstr "" +"Freagracht a mhéadú. Is féidir é a bhrath ag roinnt bogearraí frith-cheat." + +#: bottles/frontend/ui/details-preferences.blp:71 +msgid "Updating LatencyFleX, please wait…" +msgstr "LatencyFleX á nuashonrú, fan go fóill…" + +#: bottles/frontend/ui/details-preferences.blp:84 +msgid "Display" +msgstr "Taispeáin" + +#: bottles/frontend/ui/details-preferences.blp:88 +msgid "Deep Learning Super Sampling" +msgstr "Super Sampláil Foghlama Domhain" + +#: bottles/frontend/ui/details-preferences.blp:89 +msgid "" +"Increase performance at the expense of visuals using DXVK-NVAPI. Only works " +"on newer NVIDIA GPUs." +msgstr "" +"Feidhmíocht a mhéadú ar chostas na n-amhairc ag baint úsáide as DXVK-NVAPI. " +"Ní oibríonn sé ach ar GPUanna NVIDIA níos nuaí." + +#: bottles/frontend/ui/details-preferences.blp:105 +msgid "FidelityFX Super Resolution" +msgstr "FidelityFX Super Réiteach" + +#: bottles/frontend/ui/details-preferences.blp:106 +msgid "Increase performance at the expense of visuals. Only works on Vulkan." +msgstr "Feidhmíocht a mhéadú ar chostas íomhánna. Ní oibríonn sé ach ar Vulkan." + +#: bottles/frontend/ui/details-preferences.blp:108 +msgid "Manage FidelityFX Super Resolution settings" +msgstr "Bainistigh socruithe Super Resolution FidelityFX" + +#: bottles/frontend/ui/details-preferences.blp:125 +msgid "Discrete Graphics" +msgstr "Grafaicí scoite" + +#: bottles/frontend/ui/details-preferences.blp:126 +msgid "" +"Use the discrete graphics card to increase performance at the expense of " +"power consumption." +msgstr "" +"Úsáid an cárta grafaicí scoite chun feidhmíocht a mhéadú ar chostas " +"tomhaltais chumhachta." + +#: bottles/frontend/ui/details-preferences.blp:135 +msgid "Post-Processing Effects" +msgstr "Éifeachtaí Iar-Próiseála" + +#: bottles/frontend/ui/details-preferences.blp:136 +msgid "" +"Add various post-processing effects using vkBasalt. Only works on Vulkan." +msgstr "" +"Cuir éifeachtaí iar-phróiseála éagsúla le húsáid VKBasalt. Ní oibríonn sé " +"ach ar Vulkan." + +#: bottles/frontend/ui/details-preferences.blp:138 +msgid "Manage Post-Processing Layer settings" +msgstr "Bainistigh socruithe Ciseal Iarphróiseála" + +#: bottles/frontend/ui/details-preferences.blp:154 +msgid "Manage how games should be displayed on the screen using Gamescope." +msgstr "" +"Bainistigh conas ba chóir cluichí a thaispeáint ar an scáileán ag úsáid " +"Gamescope." + +#: bottles/frontend/ui/details-preferences.blp:157 +msgid "Manage Gamescope settings" +msgstr "Bainistigh socruithe Gamescope" + +#: bottles/frontend/ui/details-preferences.blp:171 +msgid "Advanced Display Settings" +msgstr "Socruithe Taispeána Ard" + +#: bottles/frontend/ui/details-preferences.blp:184 +msgid "Performance" +msgstr "Feidhmíocht" + +#: bottles/frontend/ui/details-preferences.blp:188 +msgid "Enable synchronization to increase performance of multicore processors." +msgstr "Cumasaigh sioncrónú chun feidhmíocht próiseálaithe multicore a mhéadú." + +#: bottles/frontend/ui/details-preferences.blp:189 +msgid "Synchronization" +msgstr "Sioncrónú" + +#: bottles/frontend/ui/details-preferences.blp:193 +msgid "System" +msgstr "Córas" + +#: bottles/frontend/ui/details-preferences.blp:194 +msgid "Esync" +msgstr "Esync" + +#: bottles/frontend/ui/details-preferences.blp:195 +msgid "Fsync" +msgstr "Fsync" + +#: bottles/frontend/ui/details-preferences.blp:201 +msgid "Monitor Performance" +msgstr "Monatóireacht a dhéanamh" + +#: bottles/frontend/ui/details-preferences.blp:202 +msgid "" +"Display monitoring information such as framerate, temperatures, CPU/GPU load " +"and more on OpenGL and Vulkan using MangoHud." +msgstr "" +"Taispeáin faisnéis monatóireachta cosúil le framerate, teochtaí, ualach CPU/" +"GPU agus níos mó ar OpenGL agus Vulkan ag baint úsáide as MangoHUD." + +#: bottles/frontend/ui/details-preferences.blp:210 +msgid "Feral GameMode" +msgstr "Feral GameMode" + +#: bottles/frontend/ui/details-preferences.blp:211 +msgid "" +"Apply a set of optimizations to your device. Can improve game performance." +msgstr "" +"Cuir sraith optimizations i bhfeidhm ar do ghléas. Is féidir feabhas a chur " +"ar fheidhmíocht cluiche." + +#: bottles/frontend/ui/details-preferences.blp:220 +msgid "Preload Game Files" +msgstr "Réamh-lódáil Comhaid Cluiche" + +#: bottles/frontend/ui/details-preferences.blp:221 +msgid "" +"Improve loading time when launching the game multiple times. The game will " +"take longer to start for the first time." +msgstr "" +"Feabhsú am luchtaithe agus an cluiche á seoladh arís agus arís eile Tógfaidh " +"an cluiche níos faide chun tosú den chéad uair." + +#: bottles/frontend/ui/details-preferences.blp:225 +msgid "Manage vmtouch settings" +msgstr "Bainistigh socruithe vmtouch" + +#: bottles/frontend/ui/details-preferences.blp:240 +msgid "OBS Game Capture" +msgstr "Gabháil Cluiche OBS" + +#: bottles/frontend/ui/details-preferences.blp:241 +msgid "Toggle OBS Game Capture for all Vulkan and OpenGL programs." +msgstr "Toggle OBS Cluiche Gabháil do gach clár Vulkan agus OpenGL." + +#: bottles/frontend/ui/details-preferences.blp:250 +msgid "Compatibility" +msgstr "Comhoiriúnacht" + +#: bottles/frontend/ui/details-preferences.blp:253 +msgid "Windows Version" +msgstr "Leagan Windows" + +#: bottles/frontend/ui/details-preferences.blp:256 +msgid "Updating Windows version, please wait…" +msgstr "Leagan Windows á nuashonrú, fan go fóill…" + +#: bottles/frontend/ui/details-preferences.blp:265 +msgid "Language" +msgstr "Teanga" + +#: bottles/frontend/ui/details-preferences.blp:266 +msgid "Choose the language to use with programs." +msgstr "Roghnaigh an teanga le húsáid le cláir." + +#: bottles/frontend/ui/details-preferences.blp:274 +msgid "Dedicated Sandbox" +msgstr "Bosca gainimh tiomnaithe" + +#: bottles/frontend/ui/details-preferences.blp:275 +msgid "Use a restricted/managed environment for this bottle." +msgstr "Úsáid timpeallacht srianta/bainistithe don bhuidéal seo." + +#: bottles/frontend/ui/details-preferences.blp:278 +msgid "Manage the Sandbox Permissions" +msgstr "Bainistigh Ceadanna Bosca Gaineamh" + +#: bottles/frontend/ui/details-preferences.blp:294 +msgid "Bottles Runtime" +msgstr "Am Rite Buidéil" + +#: bottles/frontend/ui/details-preferences.blp:295 +msgid "" +"Provide a bundle of extra libraries for more compatibility. Disable it if " +"you run into issues." +msgstr "" +"Cuir beart leabharlanna breise ar fáil le haghaidh níos mó comhoiriúnachta. " +"Díchumasaigh é má théann tú i bhfadhbanna." + +#: bottles/frontend/ui/details-preferences.blp:305 +msgid "Steam Runtime" +msgstr "Am rite Steam" + +#: bottles/frontend/ui/details-preferences.blp:306 +msgid "" +"Provide a bundle of extra libraries for more compatibility with Steam games. " +"Disable it if you run into issues." +msgstr "" +"Cuir beart leabharlanna breise ar fáil chun níos mó comhoiriúnachta le " +"cluichí Steam. Díchumasaigh é má théann tú i bhfadhbanna." + +#: bottles/frontend/ui/details-preferences.blp:314 +#: bottles/frontend/ui/dialog-launch-options.blp:83 +msgid "Working Directory" +msgstr "Eolaire Oibre" + +#: bottles/frontend/ui/details-preferences.blp:317 +#: bottles/frontend/ui/dialog-launch-options.blp:59 +#: bottles/frontend/ui/dialog-launch-options.blp:90 +#: bottles/frontend/ui/new.blp:150 bottles/frontend/ui/new.blp:181 +#: bottles/frontend/ui/preferences.blp:157 +msgid "Reset to Default" +msgstr "Athshocraigh go Réamhshocrú" + +#: bottles/frontend/ui/details-preferences.blp:338 +#: bottles/frontend/ui/preferences.blp:178 bottles/frontend/views/new.py:78 +#: bottles/frontend/views/preferences.py:221 +msgid "(Default)" +msgstr "(Réamhshocraithe)" + +#: bottles/frontend/ui/details-preferences.blp:346 +#: bottles/frontend/ui/dialog-dll-overrides.blp:7 +#: bottles/frontend/ui/dialog-dll-overrides.blp:12 +msgid "DLL Overrides" +msgstr "Aisghairtí DLL" + +#: bottles/frontend/ui/details-preferences.blp:356 +#: bottles/frontend/ui/dialog-env-vars.blp:20 +msgid "Environment Variables" +msgstr "Athróga Comhshaoil" + +#: bottles/frontend/ui/details-preferences.blp:366 +msgid "Manage Drives" +msgstr "Bainistigh Tiomáine" + +#: bottles/frontend/ui/details-preferences.blp:380 +msgid "Automatic Snapshots" +msgstr "Snapshots Uathoibríoch" + +#: bottles/frontend/ui/details-preferences.blp:381 +msgid "" +"Automatically create snapshots before installing software or changing " +"settings." +msgstr "" +"Cruthaigh pictiúir go huathoibríoch roimh duit bogearraí a shuiteáil nó " +"socruithe a athrú." + +#: bottles/frontend/ui/details-preferences.blp:390 +msgid "Compression" +msgstr "Comhbhrú" + +#: bottles/frontend/ui/details-preferences.blp:391 +msgid "" +"Compress snapshots to reduce space. This will slow down the creation of " +"snapshots." +msgstr "" +"Comhbhrúigh snapshots chun spás a laghdú. Déanfaidh sé seo moilliú ar " +"chruthú snapshots." + +#: bottles/frontend/ui/details-preferences.blp:400 +msgid "Use Exclusion Patterns" +msgstr "Úsáid Patrúin Eisiamh" + +#: bottles/frontend/ui/details-preferences.blp:401 +msgid "Exclude paths in snapshots." +msgstr "Eisiamh cosáin i snapshots." + +#: bottles/frontend/ui/details-preferences.blp:404 +msgid "Manage Patterns" +msgstr "Bainistigh Patrúin" + +#: bottles/frontend/ui/details-taskmanager.blp:17 +msgid "Refresh" +msgstr "Athnuachan" + +#: bottles/frontend/ui/details-taskmanager.blp:22 +msgid "Stop process" +msgstr "Stad próiseas" + +#: bottles/frontend/ui/details-versioning.blp:18 +msgid "No Snapshots Found" +msgstr "Níl aon Snapshots le fáil" + +#: bottles/frontend/ui/details-versioning.blp:19 +msgid "Create your first snapshot to start saving states of your preferences." +msgstr "" +"Cruthaigh do chéad léargas chun tosú a shábháil stáit de do chuid roghanna." + +#: bottles/frontend/ui/details-versioning.blp:54 +msgid "A short comment" +msgstr "Trácht gairid" + +#: bottles/frontend/ui/details-versioning.blp:58 +msgid "Save the bottle state." +msgstr "Sábháil stát an bhuidéil." + +#: bottles/frontend/ui/details-versioning.blp:78 +msgid "Create new Snapshot" +msgstr "Cruthaigh Snapshot nua" + +#: bottles/frontend/ui/details.blp:16 +msgid "Details" +msgstr "Sonraí" + +#: bottles/frontend/ui/details.blp:24 bottles/frontend/ui/details.blp:64 +#: bottles/frontend/ui/importer.blp:15 +msgid "Go Back" +msgstr "Téigh ar ais" + +#: bottles/frontend/ui/details.blp:75 +msgid "Operations" +msgstr "Oibríochtaí" + +#: bottles/frontend/ui/dialog-bottle-picker.blp:4 +msgid "Select Bottle" +msgstr "Roghnaigh Buidéal" + +#: bottles/frontend/ui/dialog-bottle-picker.blp:16 +#: bottles/frontend/ui/dialog-proton-alert.blp:16 +#: bottles/frontend/ui/dialog-rename.blp:15 +#: bottles/frontend/ui/dialog-run-args.blp:20 +msgid "Cancel" +msgstr "Cealaigh" + +#: bottles/frontend/ui/dialog-bottle-picker.blp:21 +msgid "Select" +msgstr "Roghnaigh" + +#: bottles/frontend/ui/dialog-bottle-picker.blp:38 +#: bottles/frontend/ui/new.blp:9 bottles/frontend/ui/new.blp:49 +#: bottles/frontend/ui/window.blp:25 +msgid "Create New Bottle" +msgstr "Cruthaigh Buidéal Nua" + +#: bottles/frontend/ui/dialog-crash-report.blp:8 +msgid "Bottles Crash Report" +msgstr "Tuarascáil ar Thumpáil" + +#: bottles/frontend/ui/dialog-crash-report.blp:18 +#: bottles/frontend/ui/dialog-duplicate.blp:22 +#: bottles/frontend/ui/dialog-gamescope.blp:23 +#: bottles/frontend/ui/dialog-launch-options.blp:16 +#: bottles/frontend/ui/dialog-upgrade-versioning.blp:22 +#: bottles/frontend/ui/dialog-vkbasalt.blp:27 bottles/frontend/ui/new.blp:26 +#: bottles/frontend/views/bottle_details.py:507 +#: bottles/frontend/views/bottle_details.py:603 +#: bottles/frontend/views/bottle_preferences.py:746 +#: bottles/frontend/views/preferences.py:212 +msgid "_Cancel" +msgstr "_Cealaigh" + +#: bottles/frontend/ui/dialog-crash-report.blp:25 +msgid "Send Report" +msgstr "Seol Tuarascáil" + +#: bottles/frontend/ui/dialog-crash-report.blp:44 +msgid "" +"Bottles crashed last time. Please fill out a report attaching the following " +"traceback to help us identify the problem preventing it from happening again." +msgstr "" +"Bhuail buidéil an uair dheireanach. Comhlánaigh tuairisc le do thoil agus an " +"t-aisrianú seo a leanas iniata leis chun cabhrú linn an fhadhb a aithint a " +"chuireann cosc uirthi tarlú arís." + +#: bottles/frontend/ui/dialog-crash-report.blp:74 +msgid "" +"We found one or more similar (or identical) reports. Please make sure to " +"check carefully that it has not already been reported before submitting a " +"new one. Each report requires effort on the part of the developers to " +"diagnose, please respect their work and make sure you don't post duplicates." +msgstr "" +"Fuaireamar tuarascáil amháin nó níos mó den chineál céanna (nó comhionann). " +"Déan cinnte seiceáil go cúramach le do thoil nár tuairiscíodh é cheana féin " +"sula gcuireann tú ceann nua isteach. Éilíonn gach tuarascáil iarracht ó " +"thaobh na bhforbróirí chun diagnóis a dhéanamh, meas a gcuid oibre le do " +"thoil agus déan cinnte nach gcuireann tú dúbailtí a phostáil." + +#: bottles/frontend/ui/dialog-crash-report.blp:89 +msgid "I still want to report." +msgstr "Ba mhaith liom tuairisciú a dhéanamh fós." + +#: bottles/frontend/ui/dialog-crash-report.blp:95 +msgid "Advanced options" +msgstr "Roghanna chun cinn" + +#: bottles/frontend/ui/dialog-deps-check.blp:13 +msgid "Incomplete package" +msgstr "Pacáiste neamhiomlán" + +#: bottles/frontend/ui/dialog-deps-check.blp:14 +msgid "" +"This version of Bottles does not seem to provide all the necessary core " +"dependencies, please contact the package maintainer or use an official " +"version." +msgstr "" +"Ní cosúil go soláthraíonn an leagan seo de Buidéil na croíspleáchas " +"riachtanacha go léir, déan teagmháil leis an gcothabhálaí pacáiste nó bain " +"úsáid as leagan oifigiúil." + +#: bottles/frontend/ui/dialog-deps-check.blp:18 +msgid "Quit" +msgstr "Scoir" + +#: bottles/frontend/ui/dialog-dll-overrides.blp:11 +msgid "" +"Dynamic Link Libraries can be specified to be builtin (provided by Wine) or " +"native (provided by the program)." +msgstr "" +"Is féidir Leabharlanna Nasc Dhinimiciúla a shonrú le bheith tógtha (a " +"sholáthraíonn Fíon) nó dúchasacha (a sholáthraíonn an clár)." + +#: bottles/frontend/ui/dialog-dll-overrides.blp:15 +msgid "New Override" +msgstr "Aisghabháil Nua" + +#: bottles/frontend/ui/dialog-dll-overrides.blp:21 +msgid "Overrides" +msgstr "Sárú" + +#: bottles/frontend/ui/dialog-drives.blp:7 +msgid "Drives" +msgstr "Tiomántáin" + +#: bottles/frontend/ui/dialog-drives.blp:24 +msgid "" +"These are paths from your host system that are mapped and recognized as " +"devices by the runner (e.g. C: D:…)." +msgstr "" +"Is cosáin iad seo ó do chóras óstach a mhapálann agus a aithníonn an " +"reathnóir mar ghléasanna (m.sh. C: D:...)." + +#: bottles/frontend/ui/dialog-drives.blp:27 +msgid "Letter" +msgstr "Litir" + +#: bottles/frontend/ui/dialog-drives.blp:49 +msgid "Existing Drives" +msgstr "Tiomáinte atá ann cheana" + +#: bottles/frontend/ui/dialog-duplicate.blp:16 +msgid "Duplicate Bottle" +msgstr "Buidéal dúblach" + +#: bottles/frontend/ui/dialog-duplicate.blp:38 +msgid "Duplicate" +msgstr "Dúblach" + +#: bottles/frontend/ui/dialog-duplicate.blp:49 +msgid "Enter a name for the duplicate of the Bottle." +msgstr "Cuir isteach ainm don dúblach den Bhuidéal." + +#: bottles/frontend/ui/dialog-duplicate.blp:69 +msgid "Duplicating…" +msgstr "Ag dúbláil…" + +#: bottles/frontend/ui/dialog-duplicate.blp:78 +#: bottles/frontend/ui/dialog-installer.blp:103 +#: bottles/frontend/ui/dialog-upgrade-versioning.blp:112 +#: bottles/frontend/views/new.py:177 +msgid "This could take a while." +msgstr "D'fhéadfadh sé seo tamall a thógáil." + +#: bottles/frontend/ui/dialog-duplicate.blp:97 +msgid "Bottle Duplicated" +msgstr "Buidéal dúbailte" + +#: bottles/frontend/ui/dialog-env-vars.blp:28 +msgid "" +"Environment variables are dynamic-named value that can affect the way " +"running processes will behave on your bottle." +msgstr "" +"Is luach dinimiciúil iad athróga comhshaoil a d'fhéadfadh dul i bhfeidhm ar " +"an mbealach a iompraíonn próisis reatha ar do bhuidéal." + +#: bottles/frontend/ui/dialog-env-vars.blp:31 +msgid "Variable Name" +msgstr "Ainm Athraitheach" + +#: bottles/frontend/ui/dialog-env-vars.blp:37 +msgid "Existing Variables" +msgstr "Athróga atá ann cheana" + +#: bottles/frontend/ui/dialog-exclusion-patterns.blp:20 +msgid "Exclusion Patterns" +msgstr "Patrúin Eisiaimh" + +#: bottles/frontend/ui/dialog-exclusion-patterns.blp:28 +msgid "" +"Define patterns that will be used to prevent some directories to being " +"versioned." +msgstr "Sainmhínigh patrúin a úsáidfear chun roinnt eolairí a chosc a leagan." + +#: bottles/frontend/ui/dialog-exclusion-patterns.blp:31 +msgid "Pattern" +msgstr "Patrún" + +#: bottles/frontend/ui/dialog-exclusion-patterns.blp:37 +msgid "Existing Patterns" +msgstr "Patrúin atá ann cheana" + +#: bottles/frontend/ui/dialog-gamescope.blp:6 +msgid "Gamescope Settings" +msgstr "Socruithe Gamescope" + +#: bottles/frontend/ui/dialog-gamescope.blp:30 +#: bottles/frontend/ui/dialog-launch-options.blp:32 +#: bottles/frontend/ui/dialog-rename.blp:20 +#: bottles/frontend/ui/dialog-vkbasalt.blp:34 +msgid "Save" +msgstr "Sábháil" + +#: bottles/frontend/ui/dialog-gamescope.blp:40 +msgid "Manage how games should be displayed." +msgstr "Manage how games should be displayed." + +#: bottles/frontend/ui/dialog-gamescope.blp:44 +msgid "Game Resolution" +msgstr "Réiteach Cluiche" + +#: bottles/frontend/ui/dialog-gamescope.blp:45 +msgid "Uses the resolution of the video game as a reference in pixels." +msgstr "Úsáideann sé réiteach an chluiche físe mar thagairt i bpicteilíní." + +#: bottles/frontend/ui/dialog-gamescope.blp:48 +#: bottles/frontend/ui/dialog-gamescope.blp:85 +msgid "Width" +msgstr "Leithead" + +#: bottles/frontend/ui/dialog-gamescope.blp:64 +#: bottles/frontend/ui/dialog-gamescope.blp:101 +msgid "Height" +msgstr "Airde" + +#: bottles/frontend/ui/dialog-gamescope.blp:81 +msgid "Window Resolution" +msgstr "Réiteach Fuinneog" + +#: bottles/frontend/ui/dialog-gamescope.blp:82 +msgid "" +"Upscales the resolution when using a resolution higher than the game " +"resolution in pixels." +msgstr "" +"Uasscálaíonn an taifeach agus taifeach níos airde ná taifeach an chluiche á " +"úsáid i bpicteilíní." + +#: bottles/frontend/ui/dialog-gamescope.blp:118 +msgid "Miscellaneous" +msgstr "Ilghnéireach" + +#: bottles/frontend/ui/dialog-gamescope.blp:121 +msgid "Frame Rate Limit" +msgstr "Teorainn Ráta Fráma" + +#: bottles/frontend/ui/dialog-gamescope.blp:137 +msgid "Frame Rate Limit When Unfocused" +msgstr "Teorainn Ráta Fráma Nuair nach bhfuil Dírithe" + +#: bottles/frontend/ui/dialog-gamescope.blp:153 +msgid "Integer Scaling" +msgstr "Scálú Sláimhir" + +#: bottles/frontend/ui/dialog-gamescope.blp:162 +msgid "Window Type" +msgstr "Cineál Fuinneog" + +#: bottles/frontend/ui/dialog-gamescope.blp:166 +msgid "Borderless" +msgstr "Gan teorainn" + +#: bottles/frontend/ui/dialog-gamescope.blp:172 +msgid "Fullscreen" +msgstr "Iomlánscáileán" + +#: bottles/frontend/ui/dialog-installer.blp:40 +msgid "Do you want to proceed with the installation?" +msgstr "Ar mhaith leat dul ar aghaidh leis an suiteáil?" + +#: bottles/frontend/ui/dialog-installer.blp:45 +msgid "Start Installation" +msgstr "Tosaigh Suiteáil" + +#: bottles/frontend/ui/dialog-installer.blp:64 +msgid "" +"This installer requires some local resources which cannot be provided " +"otherwise." +msgstr "" +"Teastaíonn roinnt acmhainní áitiúla ón suiteálaí seo nach féidir a sholáthar " +"murach é." + +#: bottles/frontend/ui/dialog-installer.blp:68 +msgid "Proceed" +msgstr "Lean ar aghaidh" + +#: bottles/frontend/ui/dialog-installer.blp:127 +msgid "Completed!" +msgstr "Críochnaithe!" + +#: bottles/frontend/ui/dialog-installer.blp:130 +msgid "Show Programs" +msgstr "Cláir Taispeáin" + +#: bottles/frontend/ui/dialog-installer.blp:148 +msgid "Installation Failed!" +msgstr "Theip ar an Suiteáil!" + +#: bottles/frontend/ui/dialog-installer.blp:149 +msgid "Something went wrong." +msgstr "Chuaigh rud éigin mícheart." + +#: bottles/frontend/ui/dialog-journal.blp:9 +msgid "All messages" +msgstr "Gach teachtaireacht" + +#: bottles/frontend/ui/dialog-journal.blp:13 +msgid "Critical" +msgstr "Criticiúil" + +#: bottles/frontend/ui/dialog-journal.blp:17 +msgid "Errors" +msgstr "Earráidí" + +#: bottles/frontend/ui/dialog-journal.blp:21 +msgid "Warnings" +msgstr "Rabhadh" + +#: bottles/frontend/ui/dialog-journal.blp:25 +msgid "Info" +msgstr "Eolas" + +#: bottles/frontend/ui/dialog-journal.blp:40 +#: bottles/frontend/ui/dialog-journal.blp:48 +msgid "Journal Browser" +msgstr "Brabhsálaí Iris" + +#: bottles/frontend/ui/dialog-journal.blp:53 +msgid "Change Logging Level." +msgstr "Athraigh Leibhéal Logála." + +#: bottles/frontend/ui/dialog-journal.blp:57 +msgid "All" +msgstr "Gach" + +#: bottles/frontend/ui/dialog-launch-options.blp:42 +msgid "Those arguments will be passed at launch." +msgstr "Ritheofar na hargóintí sin ag an seoladh." + +#: bottles/frontend/ui/dialog-launch-options.blp:43 +msgid "Custom Arguments" +msgstr "Argóintí Saincheaptha" + +#: bottles/frontend/ui/dialog-launch-options.blp:46 +msgid "Command Arguments" +msgstr "Argóintí Ordú" + +#: bottles/frontend/ui/dialog-launch-options.blp:47 +#, c-format +msgid "e.g.: VAR=value %command% -example1 -example2 -example3=hello" +msgstr "m.sh.: VAR=value %command% -example1 -example2 -example3=hello" + +#: bottles/frontend/ui/dialog-launch-options.blp:52 +msgid "Post-run Script" +msgstr "Script iar-reáchtáil" + +#. endregion +#: bottles/frontend/ui/dialog-launch-options.blp:53 +#: bottles/frontend/windows/launchoptions.py:53 +msgid "Choose a script which should be executed after run." +msgstr "Roghnaigh script ar chóir a fhorghníomhú tar éis rith." + +#: bottles/frontend/ui/dialog-launch-options.blp:70 +msgid "Choose a Script" +msgstr "Roghnaigh Script" + +#: bottles/frontend/ui/dialog-launch-options.blp:84 +#: bottles/frontend/windows/launchoptions.py:54 +msgid "Choose from where start the program." +msgstr "Roghnaigh ón áit a dtosaíonn an clár." + +#: bottles/frontend/ui/dialog-launch-options.blp:101 +#: bottles/frontend/ui/drive-entry.blp:22 +msgid "Choose a Directory" +msgstr "Roghnaigh Eolaire" + +#: bottles/frontend/ui/dialog-launch-options.blp:114 +msgid "These settings will override the default settings for this executable." +msgstr "" +"Athróidh na socruithe seo na socruithe réamhshocraithe don inúsáidte seo." + +#: bottles/frontend/ui/dialog-launch-options.blp:115 +msgid "Preferences Overrides" +msgstr "Sáraithe Roghanna" + +#: bottles/frontend/ui/dialog-launch-options.blp:119 +msgid "Reset to Bottle's Defaults" +msgstr "Athshocraigh go Réamhshocraithe Buidéal" + +#: bottles/frontend/ui/dialog-launch-options.blp:165 +msgid "Virtual Desktop" +msgstr "Deisce Fíorúil" + +#: bottles/frontend/ui/dialog-proton-alert.blp:4 +msgid "Proton Disclaimer" +msgstr "Séanadh Proton" + +#: bottles/frontend/ui/dialog-proton-alert.blp:21 +msgid "Use Proton" +msgstr "Úsáid Proton" + +#: bottles/frontend/ui/dialog-proton-alert.blp:35 +msgid "" +"Beware, using Proton-based runners in non-Steam bottles can cause problems " +"and prevent them from behaving correctly.\n" +"\n" +"We recommend using Wine-GE rather, a version of Proton meant to run outside " +"of Steam.\n" +"\n" +"Proceeding will automatically enable the Steam runtime (if present in the " +"system and detected by Bottles) in order to allow it to access the necessary " +"libraries and limit compatibility problems. Be aware that GloriousEggroll, " +"the runner's provider, is not responsible for any problems and we ask that " +"you do not report to them." +msgstr "" +"Bí cúramach, d'fhéadfadh fadhbanna a bheith ina chúis le reathaithe atá " +"bunaithe ar Próton i mbuidéil neamh-gaile agus cosc a chur orthu iompar\n" +"\n" +"Molaimid Wine-GE a úsáid ina ionad, leagan de Proton atá i gceist le rith " +"lasmuigh de Steam.\n" +"\n" +"Cuirfidh dul ar aghaidh ar aghaidh ar aghaidh ar chumas an réiteach Gaile go " +"huathoibríoch (má tá sé i láthair sa chóras agus má bhraitheann Buidéil) " +"d'fhonn ligean dó rochtain a fháil ar na leabharlanna Bí ar an eolas nach " +"bhfuil GloriouseGgroll, soláthraí an rádálaí, freagrach as aon fhadhbanna " +"agus iarraimid ort nach dtuairisciú dóibh." + +#: bottles/frontend/ui/dialog-proton-alert.blp:43 +msgid "I got it." +msgstr "Fuair mé é." + +#: bottles/frontend/ui/dialog-rename.blp:7 +msgid "Rename" +msgstr "Athainmnigh" + +#: bottles/frontend/ui/dialog-rename.blp:30 +msgid "Choose a new name for the selected program." +msgstr "Roghnaigh ainm nua don chlár roghnaithe." + +#: bottles/frontend/ui/dialog-rename.blp:33 +msgid "New Name" +msgstr "Ainm Nua" + +#: bottles/frontend/ui/dialog-run-args.blp:13 +msgid "Run With Arguments" +msgstr "Rith Le Argóintí" + +#: bottles/frontend/ui/dialog-run-args.blp:34 +#: bottles/frontend/views/bottle_details.py:404 +#: bottles/frontend/views/list.py:131 +msgid "Run" +msgstr "Rith" + +#: bottles/frontend/ui/dialog-run-args.blp:44 +msgid "Write below the arguments to be passed to the executable." +msgstr "Scríobh thíos na hargóintí atá le cur chuig an infhorghníomhaithe." + +#: bottles/frontend/ui/dialog-run-args.blp:47 +msgid "e.g.: -opengl -SkipBuildPatchPrereq" +msgstr "m.sh.: -opengl -SkipBuildPatchPrereq" + +#: bottles/frontend/ui/dialog-sandbox.blp:7 +msgid "Sandbox Settings" +msgstr "Socruithe Bosca Gaineamh" + +#: bottles/frontend/ui/dialog-sandbox.blp:25 +msgid "Share Network" +msgstr "Comhroinn Líonra" + +#: bottles/frontend/ui/dialog-sandbox.blp:34 +msgid "Share Sound" +msgstr "Comhroinn Fuaim" + +#: bottles/frontend/ui/dialog-upgrade-versioning.blp:16 +msgid "Upgrade Needed" +msgstr "Uasghrádú Teast" + +#: bottles/frontend/ui/dialog-upgrade-versioning.blp:38 +#: bottles/frontend/ui/onboard.blp:81 +msgid "Continue" +msgstr "Lean ar aghaidh" + +#: bottles/frontend/ui/dialog-upgrade-versioning.blp:47 +msgid "Launch upgrade" +msgstr "Uasghrádú Seol" + +#: bottles/frontend/ui/dialog-upgrade-versioning.blp:66 +msgid "New Versioning System" +msgstr "Córas Leagan Nua" + +#: bottles/frontend/ui/dialog-upgrade-versioning.blp:69 +msgid "The new bottle versioning system has landed." +msgstr "Tá an córas leaganaithe buidéal nua tar éis talamh." + +#: bottles/frontend/ui/dialog-upgrade-versioning.blp:83 +msgid "" +"Bottles has a whole new Versioning System that is not backwards compatible.\n" +"\n" +"To continue using versioning we need to re-initialize the bottle repository. " +"This will not delete data from your bottle but will delete all existing " +"snapshots and create a new one.\n" +"\n" +"If you need to go back to a previous snapshot before continuing, close this " +"window and restore the snapshot, then reopen the bottle to show this window " +"again.\n" +"\n" +"The old system will be discontinued in one of the next releases." +msgstr "" +"Tá Córas Leagan iomlán nua ag Buidles nach bhfuil comhoiriúnach ar ais.\n" +"\n" +"Chun leanúint ar aghaidh ag úsáid leagan ní mór dúinn stór an bhuidéil a " +"aththionsú. Ní scriosfaidh sé seo sonraí ó do bhuidéal ach scriosfaidh sé " +"gach snapshot atá ann cheana agus cruthóidh sé ceann nua.\n" +"\n" +"Más gá duit dul ar ais go léargas roimhe seo sula leanann tú ar aghaidh, dún " +"an fhuinneog seo agus déan an léargas ar ais, ansin an buidéal a athoscailt " +"chun an fhuinneog seo a thaispeáint arís.\n" +"\n" +"Cuirfear deireadh leis an seanchóras i gceann de na chéad eisiúintí eile." + +#: bottles/frontend/ui/dialog-upgrade-versioning.blp:103 +msgid "Re-initializing Repository…" +msgstr "Stór á ath-thionsnú…" + +#: bottles/frontend/ui/dialog-upgrade-versioning.blp:133 +msgid "Done! Please restart Bottles." +msgstr "Déanta! Athosaigh Buidéil." + +#. Translators: vkBasalt is a Vulkan post processing layer for Linux +#: bottles/frontend/ui/dialog-vkbasalt.blp:10 +msgid "Post-Processing Effects Settings" +msgstr "Socruithe Éifeachtaí Iar-Phró" + +#: bottles/frontend/ui/dialog-vkbasalt.blp:44 +msgid "Default" +msgstr "Réamhshocraithe" + +#: bottles/frontend/ui/dialog-vkbasalt.blp:48 +msgid "Default Settings" +msgstr "Socruithe Réamhshocrú" + +#: bottles/frontend/ui/dialog-vkbasalt.blp:57 +msgid "Effects are applied according to the list order." +msgstr "Cuirtear éifeachtaí i bhfeidhm de réir an ordú liosta." + +#: bottles/frontend/ui/dialog-vkbasalt.blp:58 +msgid "Effects" +msgstr "Éifeachtaí" + +#: bottles/frontend/ui/dialog-vkbasalt.blp:62 +msgid "Contrast Adaptive Sharpening" +msgstr "Géarú Oiriúnaitheach Co" + +#: bottles/frontend/ui/dialog-vkbasalt.blp:65 +#: bottles/frontend/ui/dialog-vkbasalt.blp:102 +msgid "Sharpness" +msgstr "Géar" + +#: bottles/frontend/ui/dialog-vkbasalt.blp:69 +#: bottles/frontend/ui/dialog-vkbasalt.blp:106 +#: bottles/frontend/ui/dialog-vkbasalt.blp:134 +#: bottles/frontend/ui/dialog-vkbasalt.blp:167 +#: bottles/frontend/ui/dialog-vkbasalt.blp:195 +#: bottles/frontend/ui/dialog-vkbasalt.blp:223 +#: bottles/frontend/ui/dialog-vkbasalt.blp:256 +#: bottles/frontend/ui/dialog-vkbasalt.blp:288 +#: bottles/frontend/ui/dialog-vkbasalt.blp:316 +#: bottles/frontend/ui/dialog-vkbasalt.blp:343 +#: bottles/frontend/ui/dialog-vkbasalt.blp:370 bottles/frontend/ui/new.blp:58 +msgid "Show Information" +msgstr "Taispeáin Faisnéis" + +#. Translators: Luma is not translatable +#: bottles/frontend/ui/dialog-vkbasalt.blp:99 +msgid "Denoised Luma Sharpening" +msgstr "Géarú Luma Dhíonaithe" + +#: bottles/frontend/ui/dialog-vkbasalt.blp:130 +msgid "Denoise" +msgstr "Denoise" + +#: bottles/frontend/ui/dialog-vkbasalt.blp:160 +msgid "Fast Approximate Anti-Aliasing" +msgstr "Frith-Aliasing Tapa Neart" + +#: bottles/frontend/ui/dialog-vkbasalt.blp:163 +msgid "Subpixel Quality" +msgstr "Cáilíocht Subpixel" + +#: bottles/frontend/ui/dialog-vkbasalt.blp:191 +msgid "Quality Edge Threshold" +msgstr "Tairseach imeall cáilíochta" + +#: bottles/frontend/ui/dialog-vkbasalt.blp:219 +msgid "Quality Edge Threshold Minimum" +msgstr "Íosta tairseach imeall cáilíochta" + +#: bottles/frontend/ui/dialog-vkbasalt.blp:249 +msgid "Subpixel Morphological Anti-Aliasing" +msgstr "Frith-Aliasing Moirfeolaíochta Subpixel" + +#: bottles/frontend/ui/dialog-vkbasalt.blp:252 +msgid "Edge Detection" +msgstr "Braite imeall" + +#: bottles/frontend/ui/dialog-vkbasalt.blp:267 +msgid "Luma" +msgstr "Luma" + +#: bottles/frontend/ui/dialog-vkbasalt.blp:273 +msgid "Color" +msgstr "Dath" + +#: bottles/frontend/ui/dialog-vkbasalt.blp:284 +msgid "Threshold" +msgstr "Tairseach" + +#: bottles/frontend/ui/dialog-vkbasalt.blp:312 +msgid "Max Search Steps" +msgstr "Céimeanna Cuardaigh Uasta" + +#: bottles/frontend/ui/dialog-vkbasalt.blp:339 +msgid "Max Search Steps Diagonal" +msgstr "Céimeanna Cuardaigh Max trasnánach" + +#: bottles/frontend/ui/dialog-vkbasalt.blp:366 +msgid "Max Corner Rounding" +msgstr "Scruinneáil Cúinne Max" + +#: bottles/frontend/ui/dialog-vkbasalt.blp:411 +msgid "" +"CAS sharpness increases the sharpness of a frame. Higher values make the " +"frame sharper, whereas values lower than 0 make the frame softer than native." +msgstr "" +"Méadaíonn géar CAS géar fráma. Déanann luachanna níos airde an fráma níos " +"géire, ach déanann luachanna níos ísle ná 0 an fráma níos boige ná dúchasach." + +#: bottles/frontend/ui/dialog-vkbasalt.blp:428 +msgid "" +"DLS sharpness increases the sharpness of a frame. Higher values make the " +"frame sharper." +msgstr "" +"Méadaíonn géar DLS géar fráma. Déanann luachanna níos airde an fráma níos " +"géire." + +#: bottles/frontend/ui/dialog-vkbasalt.blp:445 +msgid "" +"DLS denoise decreases the noise of a frame. Higher values make the frame " +"softer." +msgstr "" +"Laghdaíonn DLS denoise torann fráma. Déanann luachanna níos airde an fráma " +"níos boige." + +#: bottles/frontend/ui/dialog-vkbasalt.blp:462 +msgid "" +"FXAA subpixel quality decreases aliasing at the subpixel level. Higher " +"values make the frame softer." +msgstr "" +"Laghdaíonn cáilíocht fo-bpicteilín FXAA aliasing ag leibhéal an fho-" +"bpicteilín. Déanann luachanna níos airde an fráma níos boige." + +#: bottles/frontend/ui/dialog-vkbasalt.blp:479 +msgid "" +"FXAA edge threshold is the minimum amount of contrast required to apply the " +"FXAA algorithm. Higher values make the frame have more contrast." +msgstr "" +"Is é tairseach imeall FXAA an méid codarsnachta íosta a theastaíonn chun " +"algartam FXAA a chur i bhfeidhm. Fágann luachanna níos airde níos mó " +"codarsnachta ag an bhfráma." + +#: bottles/frontend/ui/dialog-vkbasalt.blp:496 +msgid "" +"FXAA quality edge threshold minimum is the minimum value of dark pixels that " +"are ignored by the FXAA algorithm. Higher values make FXAA ignore pixels " +"below the specified value and can lead to a performance increase." +msgstr "" +"Is é íosmhéid tairseach imeall cáilíochta FXAA an luach íosta de phicteilíní " +"dorcha a dtugann algartam FXAA neamhaird orthu. Déanann luachanna níos airde " +"neamhaird ar FXAA picteilíní faoi bhun an luacha sonraithe agus d'fhéadfadh " +"méadú feidhmíochta a bheith mar thoradh air." + +#: bottles/frontend/ui/dialog-vkbasalt.blp:513 +msgid "" +"Luma detects edges from a monochrome perspective, whereas Color detects " +"edges based on colors. Luma is more performant than Color." +msgstr "" +"Aimsíonn Luma imill ó pheirspictíocht monacrómach, ach braitheann Dath imill " +"bunaithe ar dathanna. Tá Luma níos feidhmiúla ná Dath." + +#: bottles/frontend/ui/dialog-vkbasalt.blp:530 +msgid "" +"SMAA threshold specifies the sensitivity of edge detection. Lower values " +"detect more edges at the expense of performance." +msgstr "" +"Sonraíonn tairseach SMAA íogaireacht braite imeall. Braitheann luachanna " +"níos ísle níos mó imill ar chostas na feidhmíochta." + +#: bottles/frontend/ui/dialog-vkbasalt.blp:547 +msgid "" +"SMAA max search steps specifies how many horizontal and vertical search " +"steps are performed when searching for edges." +msgstr "" +"Sonraíonn céimeanna cuardaigh uasta SMAA cé mhéad céim chuardaigh " +"cothrománach agus ingearach a dhéantar agus imill á cuardach agat." + +#: bottles/frontend/ui/dialog-vkbasalt.blp:564 +msgid "" +"SMAA max diagonal search steps specifies how many diagonal search steps are " +"performed when searching for edges." +msgstr "" +"Sonraíonn céimeanna cuardaigh trasnánach SMAA max cé mhéad céim chuardaigh " +"trasnánach a dhéantar agus imill á cuardach agat." + +#: bottles/frontend/ui/dialog-vkbasalt.blp:581 +msgid "SMAA corner rounding specifies the strength of rounding edge corners." +msgstr "" +"Sonraíonn timpeallú cúinne SMAA neart na gcoirnéil imeall timpeallaithe." + +#: bottles/frontend/ui/dll-override-entry.blp:8 +msgid "Builtin (Wine)" +msgstr "Builtin (Fíon)" + +#: bottles/frontend/ui/dll-override-entry.blp:9 +msgid "Native (Windows)" +msgstr "Dúchasach (Windows)" + +#: bottles/frontend/ui/dll-override-entry.blp:10 +msgid "Builtin, then Native" +msgstr "Builtin, ansin Dúchasach" + +#: bottles/frontend/ui/dll-override-entry.blp:11 +msgid "Native, then Builtin" +msgstr "Dúchasach, ansin Builtin" + +#: bottles/frontend/ui/dll-override-entry.blp:12 +msgid "Disabled" +msgstr "Míchumas" + +#: bottles/frontend/ui/dll-override-entry.blp:20 +#: bottles/frontend/ui/drive-entry.blp:12 +msgid "Remove" +msgstr "Bain" + +#: bottles/frontend/ui/drive-entry.blp:5 +msgid "/point/to/path" +msgstr "/point/to/path" + +#: bottles/frontend/ui/env-var-entry.blp:4 +#: bottles/frontend/ui/exclusion-pattern-entry.blp:4 +msgid "Value" +msgstr "Luach" + +#. Translators: A Wine prefix is a separate environment (C:\ drive) for the Wine program +#: bottles/frontend/ui/importer-entry.blp:21 +msgid "Wine prefix name" +msgstr "Ainm réimír fíona" + +#: bottles/frontend/ui/importer-entry.blp:28 +msgid "Manager" +msgstr "Bainisteoir" + +#: bottles/frontend/ui/importer-entry.blp:38 +msgid "This Wine prefix was already imported in Bottles." +msgstr "Iompórtáladh an réimír Fíona seo i mBuidéil cheana féin." + +#: bottles/frontend/ui/importer.blp:22 +msgid "Import a Bottle backup" +msgstr "Iompórtáil cúltaca Buid" + +#: bottles/frontend/ui/importer.blp:28 +msgid "Search again for prefixes" +msgstr "Cuardaigh arís le haghaidh réamhfhoirmeacha" + +#: bottles/frontend/ui/importer.blp:38 +msgid "No Prefixes Found" +msgstr "Níl aon réamhréamhacha aimsithe" + +#: bottles/frontend/ui/importer.blp:39 +msgid "" +"No external prefixes were found. Does Bottles have access to them?\n" +"Use the icon on the top to import a bottle from a backup." +msgstr "" +"Níor aimsíodh aon réamhfhoirmeacha seachtracha. An bhfuil rochtain ag " +"Buidéil orthu?\n" +"Úsáid an deilbhín ar an mbarr chun buidéal a iompórtáil ó chúltaca." + +#: bottles/frontend/ui/importer.blp:74 +msgid "Full Archive" +msgstr "Cartlann Iomlán" + +#: bottles/frontend/ui/installer-entry.blp:16 +msgid "Show Manifest…" +msgstr "Taispeáin Manifest…" + +#: bottles/frontend/ui/installer-entry.blp:20 +msgid "Read Review…" +msgstr "Léigh Léirmheas…" + +#: bottles/frontend/ui/installer-entry.blp:34 +msgid "Installer name" +msgstr "Ainm suiteálaí" + +#: bottles/frontend/ui/installer-entry.blp:35 +msgid "Installer description" +msgstr "Cur síos suiteá" + +#: bottles/frontend/ui/installer-entry.blp:42 +msgid "Unknown" +msgstr "Anaithnid" + +#: bottles/frontend/ui/installer-entry.blp:51 +msgid "Install this Program" +msgstr "Suiteáil an Clár seo" + +#: bottles/frontend/ui/installer-entry.blp:69 +msgid "Program Menu" +msgstr "Roghchlár Cláir" + +#: bottles/frontend/ui/library-entry.blp:33 +msgid "No Thumbnail" +msgstr "Gan Mionsamhail" + +#: bottles/frontend/ui/library-entry.blp:57 +msgid "Launch" +msgstr "Seoladh" + +#: bottles/frontend/ui/library-entry.blp:70 +#: bottles/frontend/ui/program-entry.blp:89 +msgid "Launch with Steam" +msgstr "Seoladh le Steam" + +#: bottles/frontend/ui/library-entry.blp:108 +msgid "Item name" +msgstr "Ainm an earra" + +#: bottles/frontend/ui/library-entry.blp:132 +msgid "Remove from Library" +msgstr "Bain ón Leabharlann" + +#: bottles/frontend/ui/library-entry.blp:143 +msgid "Stop" +msgstr "Stad" + +#: bottles/frontend/ui/library.blp:11 +#: bottles/frontend/windows/main_window.py:196 +msgid "Library" +msgstr "Leabharlann" + +#: bottles/frontend/ui/library.blp:12 +msgid "Add items here from your bottle's program list" +msgstr "Cuir míreanna anseo ó liosta clár do bhuidéal" + +#: bottles/frontend/ui/list-entry.blp:26 +msgid "Versioning is active in this bottle." +msgstr "Tá leagan gníomhach sa bhuidéal seo." + +#: bottles/frontend/ui/list-entry.blp:42 +msgid "This bottle looks damaged." +msgstr "Breathnaíonn an buidéal seo damáiste." + +#: bottles/frontend/ui/list-entry.blp:55 +msgid "Execute in this Bottle" +msgstr "Forghníomhú sa Bhuidéal seo" + +#: bottles/frontend/ui/list-entry.blp:69 +msgid "Run Here" +msgstr "Rith Anseo" + +#: bottles/frontend/ui/list-entry.blp:75 +msgid "" +"This bottle looks damaged, the configuration file is missing. I can try to " +"solve by creating a new configuration." +msgstr "" +"Breathnaíonn damáiste don bhuidéal seo, tá an comhad cumraíochta ar " +"iarraidh. Is féidir liom iarracht a dhéanamh a réiteach trí chumraíocht nua " +"a chruthú." + +#: bottles/frontend/ui/list.blp:12 +msgid "Search your bottles…" +msgstr "Cuardaigh do bhuidéil…" + +#: bottles/frontend/ui/list.blp:28 +msgid "Steam Proton" +msgstr "Prótón gaile" + +#: bottles/frontend/ui/list.blp:42 bottles/frontend/windows/main_window.py:191 +#: data/com.usebottles.bottles.metainfo.xml.in:7 +msgid "Bottles" +msgstr "Buidéil" + +#: bottles/frontend/ui/list.blp:49 +msgid "Create New Bottle…" +msgstr "Cruthaigh Buidéal Nua…" + +#: bottles/frontend/ui/list.blp:63 +msgid "No Results Found" +msgstr "Níl aon torthaí aimsithe" + +#: bottles/frontend/ui/list.blp:64 +msgid "Try a different search." +msgstr "Bain triail as cuardach difriúil." + +#: bottles/frontend/ui/loading.blp:13 +msgid "Starting up…" +msgstr "Ag tosú…" + +#: bottles/frontend/ui/loading.blp:22 +msgid "Continue Offline" +msgstr "Lean ar aghaidh as líne" + +#: bottles/frontend/ui/local-resource-entry.blp:4 +msgid "This resource is missing." +msgstr "Tá an acmhainn seo ar iarraidh." + +#: bottles/frontend/ui/local-resource-entry.blp:8 +msgid "Browse" +msgstr "Brabhsáil" + +#: bottles/frontend/ui/new.blp:32 +msgid "C_reate" +msgstr "C_ruthaigh" + +#: bottles/frontend/ui/new.blp:75 +msgid "_Application" +msgstr "_Feidhmchlár" + +#: bottles/frontend/ui/new.blp:88 +msgid "_Gaming" +msgstr "_Cearrbhachas" + +#: bottles/frontend/ui/new.blp:101 +msgid "C_ustom" +msgstr "S_aincheaptha" + +#: bottles/frontend/ui/new.blp:114 +msgid "Custom" +msgstr "Saincheaptha" + +#: bottles/frontend/ui/new.blp:118 +msgid "Share User Directory" +msgstr "Comhroinn eolaire úsáideora" + +#: bottles/frontend/ui/new.blp:119 +msgid "" +"This makes the user directory discoverable in the bottle, at the risk of " +"sharing personal information to Windows software. This option cannot be " +"changed after the bottle has been created." +msgstr "" +"Déanann sé seo an eolaire úsáideora a aimsiú sa bhuidéal, ar an mbaol " +"faisnéis phearsanta a roinnt le bogearraí Windows. Ní féidir an rogha seo a " +"athrú tar éis an buidéal a chruthú." + +#: bottles/frontend/ui/new.blp:136 +msgid "Architecture" +msgstr "Ailtireacht" + +#: bottles/frontend/ui/new.blp:137 +msgid "32-bit should only be used if strictly necessary." +msgstr "Níor chóir 32-giotán a úsáid ach amháin más gá go docht." + +#: bottles/frontend/ui/new.blp:146 +msgid "Import a custom configuration." +msgstr "Cumraíocht saincheaptha a iompórtáil." + +#: bottles/frontend/ui/new.blp:176 +msgid "Bottle Directory" +msgstr "Eolaire Buidéal" + +#: bottles/frontend/ui/new.blp:177 +msgid "Directory that will contain the data of this bottle." +msgstr "Eolaire ina mbeidh sonraí an bhuidéil seo." + +#: bottles/frontend/ui/new.blp:249 +msgid "_Close" +msgstr "_Dún" + +#: bottles/frontend/ui/new.blp:281 +msgid "This name is unavailable, please try another." +msgstr "Níl an t-ainm seo ar fáil, déan iarracht eile le do thoil." + +#: bottles/frontend/ui/onboard.blp:34 +msgid "Previous" +msgstr "Roimhe Seo" + +#: bottles/frontend/ui/onboard.blp:59 +msgid "Welcome to Bottles" +msgstr "Fáilte go Buidéil" + +#: bottles/frontend/ui/onboard.blp:60 +msgid "Run Windows Software on Linux." +msgstr "Rith Bogearraí Windows ar Linux." + +#: bottles/frontend/ui/onboard.blp:65 +msgid "Windows in Bottles" +msgstr "Fuinneoga i mBuidéil" + +#: bottles/frontend/ui/onboard.blp:66 +msgid "" +"Bottles uses compatibility runners to provide isolated containerized Windows-" +"like environments where programs run." +msgstr "" +"Úsáideann Buidéil reathaí comhoiriúnachta chun timpeallachtaí aonraithe atá " +"cosúil le coimeádán Windows a sholáthar ina reáchtálann cláir." + +#: bottles/frontend/ui/onboard.blp:72 +msgid "Almost Done" +msgstr "Beagnach Déanta" + +#: bottles/frontend/ui/onboard.blp:73 +msgid "We need a few more minutes to set everything up…" +msgstr "Teastaíonn cúpla nóiméad eile uainn chun gach rud a shocrú…" + +#: bottles/frontend/ui/onboard.blp:105 +msgid "All Ready!" +msgstr "Gach Réidh!" + +#: bottles/frontend/ui/onboard.blp:114 +msgid "Please Finish the setup first" +msgstr "Críochnaigh an socrú ar dtús" + +#: bottles/frontend/ui/onboard.blp:120 +msgid "Start using Bottles" +msgstr "Tosaigh ag úsáid Buidéil" + +#: bottles/frontend/ui/onboard.blp:141 +msgid "Next" +msgstr "Ar Aghaidh" + +#: bottles/frontend/ui/preferences.blp:5 bottles/frontend/ui/window.blp:86 +msgid "Preferences" +msgstr "Roghanna" + +#: bottles/frontend/ui/preferences.blp:12 +#: bottles/frontend/ui/preferences.blp:40 +msgid "General" +msgstr "Ginearálta" + +#: bottles/frontend/ui/preferences.blp:15 +msgid "Appearance" +msgstr "Dealramh" + +#: bottles/frontend/ui/preferences.blp:18 +msgid "Dark Mode" +msgstr "Mód Dorcha" + +#: bottles/frontend/ui/preferences.blp:19 +msgid "Whether Bottles should use the dark color scheme." +msgstr "Cibé ar chóir do Bhuidéil an scéim dathanna dorcha a úsáid." + +#: bottles/frontend/ui/preferences.blp:29 +msgid "Show Update Date" +msgstr "Taispeáin Dáta Nuashonrú" + +#: bottles/frontend/ui/preferences.blp:30 +msgid "Whether to show the update date in the bottle list." +msgstr "Cibé an dtaispeántar an dáta nuashonraithe ar liosta na buidéil." + +#: bottles/frontend/ui/preferences.blp:43 +#: data/com.usebottles.bottles.gschema.xml:51 +msgid "Notifications" +msgstr "Fógraí" + +#: bottles/frontend/ui/preferences.blp:44 +msgid "Show notifications for downloads and installs." +msgstr "Taispeáin fógraí maidir le híoslódálacha agus suiteálacha." + +#: bottles/frontend/ui/preferences.blp:53 +msgid "Temp Files" +msgstr "Comhaid Teochta" + +#: bottles/frontend/ui/preferences.blp:54 +msgid "Clean temp files when Bottles launches?" +msgstr "Glan comhaid teochta nuair a sheolann Buidéal?" + +#: bottles/frontend/ui/preferences.blp:63 +msgid "Close Bottles After Starting a Program" +msgstr "Dún Buidéil Tar éis Clár a Thosú" + +#: bottles/frontend/ui/preferences.blp:64 +msgid "Close Bottles after starting a program from the file manager." +msgstr "Dún Buidéil tar éis clár a thosú ón mbainisteoir comhad." + +#: bottles/frontend/ui/preferences.blp:74 +msgid "Integrations" +msgstr "Comhtháthú" + +#: bottles/frontend/ui/preferences.blp:77 +msgid "Steam Proton Prefixes" +msgstr "Réamhfhoirmeacha prótóin gaile" + +#: bottles/frontend/ui/preferences.blp:78 +msgid "List and manage Steam Proton prefixes." +msgstr "Prefixí Steam Proton a liostáil agus a bhainistiú." + +#: bottles/frontend/ui/preferences.blp:98 +msgid "List Steam Apps in Programs List" +msgstr "Liosta Steam Apps i Liosta Cláir" + +#: bottles/frontend/ui/preferences.blp:99 +msgid "Requires Steam for Windows installed in the bottle." +msgstr "Éilíonn Steam le haghaidh Windows suiteáilte sa bhuidéal." + +#: bottles/frontend/ui/preferences.blp:108 +msgid "List Epic Games in Programs List" +msgstr "Liosta Cluichí Eipeach i Liosta Cláir" + +#: bottles/frontend/ui/preferences.blp:109 +msgid "Requires Epic Games Store installed in the bottle." +msgstr "Éilíonn Siopa Cluichí Epic suiteáilte sa bhuidéal." + +#: bottles/frontend/ui/preferences.blp:118 +msgid "List Ubisoft Games in Programs List" +msgstr "Liosta Cluichí Ubisoft i Liosta Cláir" + +#: bottles/frontend/ui/preferences.blp:119 +msgid "Requires Ubisoft Connect installed in the bottle." +msgstr "Éilíonn Ubisoft Connect suiteáilte sa bhuidéal." + +#: bottles/frontend/ui/preferences.blp:129 +msgid "Advanced" +msgstr "Ardleibhéal" + +#: bottles/frontend/ui/preferences.blp:132 +msgid "Pre-Release" +msgstr "Réamh-eisiúint" + +#: bottles/frontend/ui/preferences.blp:133 +msgid "Display unstable versions of runners and components." +msgstr "Taispeáin leaganacha éagobhsaí de reathaí agus comhpháirteanna." + +#: bottles/frontend/ui/preferences.blp:142 +msgid "Force Offline Mode" +msgstr "Fórsa Mód As Líne" + +#: bottles/frontend/ui/preferences.blp:143 +msgid "" +"Force disable any network activity even with available network connection." +msgstr "" +"Déan aon ghníomhaíocht líonra a dhíchumasú fiú má tá nasc líonra ar fáil." + +#: bottles/frontend/ui/preferences.blp:152 +msgid "Bottles Directory" +msgstr "Eolaire Buidéil" + +#: bottles/frontend/ui/preferences.blp:153 +msgid "Directory that contains the data of your Bottles." +msgstr "Eolaire ina bhfuil sonraí do bhuidéil." + +#: bottles/frontend/ui/preferences.blp:188 +msgid "Runners" +msgstr "Reathaitheoirí" + +#: bottles/frontend/ui/preferences.blp:202 +msgid "Bottles is running in offline mode, so runners are not available." +msgstr "Tá buidéil ag rith i mód as líne, mar sin níl reathaithe ar fáil." + +#: bottles/frontend/ui/preferences.blp:236 +msgid "DLL Components" +msgstr "comhpháirteanna DLL" + +#: bottles/frontend/ui/preferences.blp:250 +msgid "Bottles is running in offline mode, so DLLs are not available." +msgstr "Tá buidéil ag rith i mód as líne, mar sin níl DLLanna ar fáil." + +#: bottles/frontend/ui/preferences.blp:282 +msgid "DXVK-NVAPI" +msgstr "DXVK-NVAPI" + +#: bottles/frontend/ui/preferences.blp:295 +msgid "Core" +msgstr "Croí" + +#: bottles/frontend/ui/preferences.blp:299 +msgid "Runtime" +msgstr "Am rite" + +#: bottles/frontend/ui/preferences.blp:303 +msgid "WineBridge" +msgstr "WineBridge" + +#: bottles/frontend/ui/preferences.blp:309 +#: data/com.usebottles.bottles.gschema.xml:71 +msgid "Experiments" +msgstr "Turgnaimh" + +#: bottles/frontend/ui/preferences.blp:312 +msgid "" +"These features are under heavy development and may be unstable, expect bugs " +"and breakage." +msgstr "" +"Tá na gnéithe seo á bhforbairt go trom agus d’fhéadfadh siad a bheith " +"éagobhsaí, ag súil le fabhtanna agus briste." + +#: bottles/frontend/ui/preferences.blp:315 +msgid "Sandbox per bottle" +msgstr "Bosca gainimh in aghaidh an bhuidéal" + +#: bottles/frontend/ui/preferences.blp:316 +msgid "In early development." +msgstr "I bhforbairt luath." + +#: bottles/frontend/ui/program-entry.blp:19 +msgid "Launch with Terminal" +msgstr "Seoladh le Críochfort" + +#: bottles/frontend/ui/program-entry.blp:25 +msgid "Browse Path" +msgstr "Brabhsáil Conair" + +#: bottles/frontend/ui/program-entry.blp:39 +msgid "Change Launch Options…" +msgstr "Athraigh Roghanna Seolta…" + +#: bottles/frontend/ui/program-entry.blp:43 +msgid "Add to Library" +msgstr "Cuir leis an Leabharlann" + +#: bottles/frontend/ui/program-entry.blp:47 +msgid "Add Desktop Entry" +msgstr "Cuir Iontráil Deisce leis" + +#: bottles/frontend/ui/program-entry.blp:51 +msgid "Add to Steam" +msgstr "Cuir le Steam" + +#: bottles/frontend/ui/program-entry.blp:55 +msgid "Rename…" +msgstr "Athainmnigh…" + +#: bottles/frontend/ui/program-entry.blp:62 +msgid "Hide Program" +msgstr "Clár i bhfolach" + +#: bottles/frontend/ui/program-entry.blp:66 +msgid "Show Program" +msgstr "Clár Taispeáin" + +#: bottles/frontend/ui/program-entry.blp:70 +msgid "Remove from List" +msgstr "Bain ón Liosta" + +#: bottles/frontend/ui/program-entry.blp:83 +msgid "Program name" +msgstr "Ainm an chláir" + +#. Translators: id as identification +#: bottles/frontend/ui/state-entry.blp:8 +msgid "State id" +msgstr "ID Stáit" + +#: bottles/frontend/ui/state-entry.blp:9 +msgid "State comment" +msgstr "Trácht stáit" + +#: bottles/frontend/ui/state-entry.blp:16 +msgid "Restore this Snapshot" +msgstr "Athchóirigh an Snapshot seo" + +#: bottles/frontend/ui/task-entry.blp:19 +msgid "Delete message" +msgstr "Scrios teachtaireacht" + +#: bottles/frontend/ui/window.blp:40 +msgid "Main Menu" +msgstr "Príomh-roghchlár" + +#: bottles/frontend/ui/window.blp:54 +msgid "" +"You don't seem connected to the internet. Without it you will not be able to " +"download essential components. Click this icon when you have reestablished " +"the connection." +msgstr "" +"Is cosúil nach bhfuil tú ceangailte leis an idirlíon. Gan é ní bheidh tú in " +"ann comhpháirteanna riachtanacha a íoslódáil. Cliceáil ar an deilbhín seo " +"nuair a bheidh an nasc athbhunaithe agat." + +#: bottles/frontend/ui/window.blp:79 +msgid "Import…" +msgstr "Iompórtáil…" + +#: bottles/frontend/ui/window.blp:91 +msgid "Help" +msgstr "Cabhair" + +#: bottles/frontend/ui/window.blp:96 +msgid "About Bottles" +msgstr "Maidir le Buidéil" + +#: bottles/frontend/views/bottle_details.py:193 +#, python-brace-format +msgid "File \"{0}\" is not a .exe or .msi file" +msgstr "Ní comhad.exe nó .msi é comhad \"{0}\"" + +#: bottles/frontend/views/bottle_details.py:209 +#, python-format +msgid "Updated: %s" +msgstr "Nuashonraithe: %s" + +#: bottles/frontend/views/bottle_details.py:270 +#, python-brace-format +msgid "\"{0}\" added" +msgstr "Cuireadh \"{0}\" leis" + +#: bottles/frontend/views/bottle_details.py:273 +#: bottles/frontend/views/bottle_details.py:401 +#: bottles/frontend/views/list.py:128 +msgid "Select Executable" +msgstr "Roghnaigh Infheidhmithe" + +#: bottles/frontend/views/bottle_details.py:276 +msgid "Add" +msgstr "Cuir" + +#: bottles/frontend/views/bottle_details.py:349 +msgid "Hide Hidden Programs" +msgstr "Folaigh Cláir i bhfolach" + +#: bottles/frontend/views/bottle_details.py:386 +#: bottles/frontend/widgets/library.py:163 +#: bottles/frontend/widgets/program.py:184 +#, python-brace-format +msgid "Launching \"{0}\"…" +msgstr "Ag seoladh \"{0}\"…" + +#: bottles/frontend/views/bottle_details.py:416 +msgid "Be Aware of Sandbox" +msgstr "Bí ar an eolas faoi bhosca gainimh" + +#: bottles/frontend/views/bottle_details.py:417 +msgid "" +"Bottles is running in a sandbox, a restricted permission environment needed " +"to keep you safe. If the program won't run, consider moving inside the " +"bottle (3 dots icon on the top), then launch from there." +msgstr "" +"Tá buidéil ag rith i mbosca gainimh, timpeallacht cheada srianta a " +"theastaíonn chun tú a choinneáil sábháilte. Mura ritheann an clár, smaoinigh " +"ar bhogadh taobh istigh den bhuidéal (deilbhín 3 ponc ar an mbarr), ansin " +"seoladh as sin." + +#: bottles/frontend/views/bottle_details.py:419 +#: bottles/frontend/views/bottle_details.py:528 +#: bottles/frontend/windows/main_window.py:223 +msgid "_Dismiss" +msgstr "_Díbhunaigh" + +#: bottles/frontend/views/bottle_details.py:432 +msgid "Select the location where to save the backup config" +msgstr "Roghnaigh an suíomh áit a shábháil an cumraíocht chúltaca" + +#: bottles/frontend/views/bottle_details.py:434 +msgid "Export" +msgstr "Easpórtáil" + +#: bottles/frontend/views/bottle_details.py:436 +msgid "Select the location where to save the backup archive" +msgstr "Roghnaigh an suíomh áit a shábháil an cartlann cúltaca" + +#: bottles/frontend/views/bottle_details.py:438 +msgid "Backup" +msgstr "Cúltaca" + +#: bottles/frontend/views/bottle_details.py:443 +#, python-brace-format +msgid "Backup created for \"{0}\"" +msgstr "Cúltaca cruthaithe do \"{0}\"" + +#: bottles/frontend/views/bottle_details.py:445 +#, python-brace-format +msgid "Backup failed for \"{0}\"" +msgstr "Theip ar chúltaca do \"{0}\"" + +#: bottles/frontend/views/bottle_details.py:504 +msgid "Are you sure you want to permanently delete \"{}\"?" +msgstr "An bhfuil tú cinnte gur mhaith leat \"{}\" a scriosadh go buan?" + +#: bottles/frontend/views/bottle_details.py:505 +msgid "" +"This will permanently delete all programs and settings associated with it." +msgstr "Scriosfaidh sé seo gach clár agus socruithe a bhaineann leis go buan." + +#: bottles/frontend/views/bottle_details.py:508 +#: bottles/frontend/views/bottle_preferences.py:747 +msgid "_Delete" +msgstr "_Scrios" + +#: bottles/frontend/views/bottle_details.py:524 +msgid "Missing Runner" +msgstr "Rathóir ar iarraidh" + +#: bottles/frontend/views/bottle_details.py:525 +msgid "" +"The runner requested by this bottle is missing. Install it through the " +"Bottles preferences or choose a new one to run applications." +msgstr "" +"Tá an rádálaí a iarrann an buidéal seo ar iarraidh. Suiteáil é trí na " +"roghanna Buidéil nó roghnaigh ceann nua chun feidhmchláir a reáchtáil." + +#: bottles/frontend/views/bottle_details.py:600 +msgid "Are you sure you want to force stop all processes?" +msgstr "" +"An bhfuil tú cinnte gur mhaith leat gach próiseas a stopadh a chur i " +"bhfeidhm?" + +#: bottles/frontend/views/bottle_details.py:601 +msgid "This can cause data loss, corruption, and programs to malfunction." +msgstr "" +"Féadfaidh sé seo a bheith ina chúis le caillteanas sonraí, éilliú, agus " +"mífheidhmiú cláir." + +#: bottles/frontend/views/bottle_details.py:604 +msgid "Force _Stop" +msgstr "Fórsa _Stad" + +#: bottles/frontend/views/bottle_preferences.py:195 +msgid "This feature is unavailable on your system." +msgstr "Níl an ghné seo ar fáil ar do chóras." + +#: bottles/frontend/views/bottle_preferences.py:196 +msgid "{} To add this feature, please run flatpak install" +msgstr "{} Chun an ghné seo a chur leis, reáchtáil suiteáil flatpak" + +#: bottles/frontend/views/bottle_preferences.py:246 +msgid "This bottle name is already in use." +msgstr "Tá an t-ainm buidéil seo in úsáid cheana féin." + +#: bottles/frontend/views/bottle_preferences.py:301 +#: bottles/frontend/windows/launchoptions.py:240 +msgid "Select Working Directory" +msgstr "Roghnaigh Eolaire oibre" + +#: bottles/frontend/views/bottle_preferences.py:422 +msgid "Directory that contains the data of \"{}\"." +msgstr "Eolaire ina bhfuil sonraí \"{}\"." + +#: bottles/frontend/views/bottle_preferences.py:743 +msgid "Are you sure you want to delete all snapshots?" +msgstr "An bhfuil tú cinnte gur mhaith leat gach snapshot a scriosadh?" + +#: bottles/frontend/views/bottle_preferences.py:744 +msgid "This will delete all snapshots but keep your files." +msgstr "Scriosfaidh sé seo gach snapshot ach coinneoidh sé do chuid comhad." + +#: bottles/frontend/views/bottle_versioning.py:90 +msgid "Please migrate to the new Versioning system to create new states." +msgstr "" +"Imirgh chuig an gcóras leaganaithe nua le do thoil chun stáit nua a chruthú." + +#: bottles/frontend/views/details.py:153 +msgid "Installers" +msgstr "Suiteálaithe" + +#: bottles/frontend/views/details.py:234 +msgid "Operations in progress, please wait." +msgstr "Oibríochtaí atá ar siúl, fan le do thoil." + +#: bottles/frontend/views/details.py:239 +msgid "Return to your bottles." +msgstr "Fill ar do bhuidéil." + +#: bottles/frontend/views/importer.py:92 +msgid "Backup imported successfully" +msgstr "Cúltaca allmhairithe" + +#: bottles/frontend/views/importer.py:94 +msgid "Import failed" +msgstr "Theip ar iompórtá" + +#: bottles/frontend/views/importer.py:108 +#: bottles/frontend/views/importer.py:145 +msgid "Importing backup…" +msgstr "Cúltaca á iompórtáil…" + +#: bottles/frontend/views/importer.py:117 +msgid "Select a Backup Archive" +msgstr "Roghnaigh Cartlann Cúltaca" + +#: bottles/frontend/views/importer.py:120 +#: bottles/frontend/views/importer.py:157 +msgid "Import" +msgstr "Allmhairiú" + +#: bottles/frontend/views/importer.py:154 bottles/frontend/views/new.py:136 +msgid "Select a Configuration File" +msgstr "Roghnaigh Comhad Cumraíochta" + +#: bottles/frontend/views/list.py:60 bottles/frontend/views/list.py:66 +msgid "N/A" +msgstr "N/A" + +#. Set tooltip text +#: bottles/frontend/views/list.py:91 +#, python-brace-format +msgid "Run executable in \"{self.config.Name}\"" +msgstr "Rith inrite i \"{self.config.Name}\"" + +#: bottles/frontend/views/list.py:118 +#, python-brace-format +msgid "Launching \"{0}\" in \"{1}\"…" +msgstr "Ag seoladh \"{0}\" in \"{1}\"…" + +#: bottles/frontend/views/list.py:235 +msgid "Your Bottles" +msgstr "Do Bhuidéil" + +#: bottles/frontend/views/loading.py:46 +#, python-brace-format +msgid "Downloading ~{0} of packages…" +msgstr "~{0} pacáiste á n-íoslódáil…" + +#: bottles/frontend/views/loading.py:47 +#, python-brace-format +msgid "Fetched {0} of {1} packages" +msgstr "Fuarthas {0} de {1} pacáistí" + +#: bottles/frontend/views/new.py:157 +msgid "Select Bottle Directory" +msgstr "Roghnaigh Eolaire Buid" + +#: bottles/frontend/views/new.py:176 +msgid "Creating Bottle…" +msgstr "Buidéal á Chruthú…" + +#: bottles/frontend/views/new.py:221 +msgid "Unable to Create Bottle" +msgstr "Ní féidir Buidéal a Chruthú" + +#: bottles/frontend/views/new.py:225 +msgid "Bottle failed to create with one or more errors." +msgstr "Theip ar bhuidéal a chruthú le earráid amháin nó níos mó." + +#. Show success +#: bottles/frontend/views/new.py:232 +msgid "Bottle Created" +msgstr "Buidéal Cruthaithe" + +#: bottles/frontend/views/new.py:233 +#, python-brace-format +msgid "\"{0}\" was created successfully." +msgstr "Cruthaíodh \"{0}\" go rathúil." + +#: bottles/frontend/views/preferences.py:134 +msgid "Steam was not found or Bottles does not have enough permissions." +msgstr "Níor aimsíodh gaile nó níl go leor ceadanna ag Buidéil." + +#: bottles/frontend/views/preferences.py:187 +msgid "Select Bottles Path" +msgstr "Roghnaigh Conair Buidéal" + +#: bottles/frontend/views/preferences.py:209 +msgid "Relaunch Bottles?" +msgstr "Buidéil Athsheolta?" + +#: bottles/frontend/views/preferences.py:210 +msgid "" +"Bottles will need to be relaunched to use this directory.\n" +"\n" +"Be sure to close every program launched from Bottles before relaunching " +"Bottles, as not doing so can cause data loss, corruption and programs to " +"malfunction." +msgstr "" +"Beidh gá le buidéil a athsheoladh chun an t-eolaire seo a úsáid.\n" +"\n" +"Bí cinnte gach clár a sheoltar ó Bhuidéil a dhúnadh sula n-athsheoltar " +"Buidéil, mar mura ndéantar amhlaidh d’fhéadfadh caillteanas sonraí, éilliú " +"agus cláir a bheith mífheidhmithe." + +#: bottles/frontend/views/preferences.py:213 +msgid "_Relaunch" +msgstr "_Athsheoladh" + +#: bottles/frontend/views/preferences.py:306 +msgid "Based on Valve's Wine, includes Staging and Proton patches." +msgstr "Bunaithe ar Fíon Valve, tá paistí Stáitse agus Prótón san áireamh." + +#: bottles/frontend/views/preferences.py:307 +msgid "Based on Wine upstream, includes Staging and Proton patches." +msgstr "" +"Bunaithe ar Fíon suas an sruth, tá paistí Stáitse agus Prótón san áireamh." + +#: bottles/frontend/views/preferences.py:308 +msgid "" +"Based on the most recent bleeding-edge Valve's Proton Experimental Wine, " +"includes Staging and custom patches. This is meant to be used with non-steam " +"games outside of Steam." +msgstr "" +"Bunaithe ar an bhFíon Turgnamhach Prótón Valve is déanaí, tá Stáitseáil agus " +"paistí saincheaptha ann. Tá sé i gceist é seo a úsáid le cluichí neamh-gaile " +"lasmuigh de Steam." + +#: bottles/frontend/views/preferences.py:311 +msgid "" +"Based on Wine upstream, Staging, Staging-TkG and Proton patchset optionally " +"available." +msgstr "" +"Bunaithe ar phaisset Fíon suas an sruth, Staging, Staging-TKG agus Proton ar " +"fáil go roghnach." + +#: bottles/frontend/views/preferences.py:313 +msgid "Based on Wine upstream, includes Staging patches." +msgstr "Bunaithe ar Fíon suas an sruth, tá paistí stáitse san áireamh." + +#: bottles/frontend/views/preferences.py:314 +msgid "" +"Based on most recent bleeding-edge Valve's Proton Experimental, includes " +"Staging and custom patches. Requires the Steam Runtime turned on." +msgstr "" +"Bunaithe ar Turgnamhach Prótón Valve is déanaí ar imeall fuiliúcháin, tá " +"stáisiú agus paistí saincheaptha ann. Éilíonn an Rúntime Gaile a chasadh air." + +#: bottles/frontend/views/preferences.py:317 +msgid "Other Wine runners" +msgstr "Reathaithe fíona eile" + +#: bottles/frontend/views/preferences.py:318 +msgid "Other Proton runners" +msgstr "Reathaithe Prótóin eile" + +#: bottles/frontend/widgets/component.py:76 +msgid "Upgrade" +msgstr "Uasghrádú" + +#: bottles/frontend/widgets/component.py:142 +msgid "Installing…" +msgstr "Ag suiteáil…" + +#: bottles/frontend/widgets/dependency.py:107 +#: bottles/frontend/widgets/installer.py:81 +#, python-brace-format +msgid "Manifest for {0}" +msgstr "Léiriú do {0}" + +#: bottles/frontend/widgets/dependency.py:172 +#, python-brace-format +msgid "\"{0}\" uninstalled" +msgstr "\"{0}\" díshuiteáilte" + +#: bottles/frontend/widgets/dependency.py:174 +#, python-brace-format +msgid "\"{0}\" installed" +msgstr "\"{0}\" suiteáilte" + +#: bottles/frontend/widgets/dependency.py:188 +#, python-brace-format +msgid "\"{0}\" failed to install" +msgstr "Theip ar \"{0}\" a shuiteáil" + +#: bottles/frontend/widgets/importer.py:68 +#, python-brace-format +msgid "\"{0}\" imported" +msgstr "\"{0}\" allmhairithe" + +#: bottles/frontend/widgets/installer.py:49 +msgid "" +"This application may work poorly. The installer was configured to provide " +"the best possible experience, but expect glitches, instability and lack of " +"working features." +msgstr "" +"D'fhéadfadh an feidhmchlár seo oibriú go dona. Cumraíodh an suiteálaí chun " +"an taithí is fearr is féidir a sholáthar, ach súil le glitches, " +"éagobhsaíocht agus easpa gnéithe oibre." + +#: bottles/frontend/widgets/installer.py:50 +msgid "" +"This program works with noticeable glitches, but these glitches do not " +"affect the application's functionality." +msgstr "" +"Oibríonn an clár seo le glitches suntasacha, ach ní dhéanann na glitches seo " +"difear do fheidhmiúlacht an fheidhmchláir." + +#: bottles/frontend/widgets/installer.py:51 +msgid "This program works with minor glitches." +msgstr "Oibríonn an clár seo le mionghabhálacha." + +#: bottles/frontend/widgets/installer.py:52 +msgid "This program works perfectly." +msgstr "Oibríonn an clár seo go foirfe." + +#: bottles/frontend/widgets/installer.py:90 +#, python-brace-format +msgid "Review for {0}" +msgstr "Léirmheas ar {0}" + +#: bottles/frontend/widgets/library.py:176 +#: bottles/frontend/widgets/program.py:194 +#, python-brace-format +msgid "Stopping \"{0}\"…" +msgstr "Ag stopadh \"{0}\"…" + +#: bottles/frontend/widgets/program.py:190 +#, python-brace-format +msgid "Launching \"{0}\" with Steam…" +msgstr "Ag seoladh \"{0}\" le Steam…" + +#: bottles/frontend/widgets/program.py:214 +#, python-brace-format +msgid "\"{0}\" hidden" +msgstr "\"{0}\" i bhfolach" + +#: bottles/frontend/widgets/program.py:216 +#, python-brace-format +msgid "\"{0}\" showed" +msgstr "Taispeáin \"{0}\"" + +#: bottles/frontend/widgets/program.py:242 +#, python-brace-format +msgid "\"{0}\" removed" +msgstr "\"{0}\" bainte" + +#: bottles/frontend/widgets/program.py:274 +#, python-brace-format +msgid "\"{0}\" renamed to \"{1}\"" +msgstr "Athainmnigh \"{0}\" go \"{1}\"" + +#: bottles/frontend/widgets/program.py:297 +#, python-brace-format +msgid "Desktop Entry created for \"{0}\"" +msgstr "Iontráil deisce cruthaithe do \"{0}\"" + +#: bottles/frontend/widgets/program.py:313 +#, python-brace-format +msgid "\"{0}\" added to your library" +msgstr "Cuireadh \"{0}\" le do leabharlann" + +#: bottles/frontend/widgets/program.py:331 +#, python-brace-format +msgid "\"{0}\" added to your Steam library" +msgstr "Cuireadh \"{0}\" le do leabharlann Steam" + +#: bottles/frontend/windows/crash.py:33 +msgid "Show report" +msgstr "Taispeáin tuarascáil" + +#: bottles/frontend/windows/crash.py:80 +msgid "" +" This issue was reported 5 times and cannot be sent again.\n" +" Report your feedback in one of the below existing reports." +msgstr "" +" Tuairiscíodh an tsaincheist seo 5 huaire agus ní féidir é a " +"sheoladh arís.\n" +" Tuairisc d'aiseolas i gceann de na tuarascálacha atá ann thíos." + +#: bottles/frontend/windows/display.py:102 +msgid "Updating display settings, please wait…" +msgstr "Socruithe taispeána á nuashonrú, fan go fóill…" + +#: bottles/frontend/windows/display.py:114 +msgid "Display settings updated" +msgstr "Socruithe taispeána nuash" + +#: bottles/frontend/windows/dlloverrides.py:136 +msgid "No overrides found." +msgstr "Níor aimsíodh aon fhorlíonadh." + +#: bottles/frontend/windows/drives.py:71 +msgid "Select Drive Path" +msgstr "Roghnaigh Conair Tiomána" + +#: bottles/frontend/windows/envvars.py:135 +msgid "No environment variables defined." +msgstr "Níl aon athróga comhshaoil sainithe." + +#: bottles/frontend/windows/exclusionpatterns.py:105 +msgid "No exclusion patterns defined." +msgstr "Ní shainigh aon phatrúin eisiaimh." + +#: bottles/frontend/windows/generic.py:24 +msgid "An error has occurred." +msgstr "Tharla earráid." + +#: bottles/frontend/windows/generic.py:91 +#: bottles/frontend/windows/generic.py:137 +#: bottles/frontend/windows/generic.py:182 +msgid "Copy to clipboard" +msgstr "Cóipeáil chuig gearr" + +#: bottles/frontend/windows/installer.py:62 +msgid "Select Resource File" +msgstr "Roghnaigh Comhad Acmhainn" + +#: bottles/frontend/windows/installer.py:109 +msgid "Installing Windows dependencies…" +msgstr "Ag suiteáil spleáchais Windows…" + +#: bottles/frontend/windows/installer.py:110 +msgid "Configuring the bottle…" +msgstr "An buidéal á chumrú…" + +#: bottles/frontend/windows/installer.py:111 +msgid "Processing installer steps…" +msgstr "Céimeanna suiteálaí á bpróiseáil…" + +#: bottles/frontend/windows/installer.py:112 +msgid "Installing the {}…" +msgstr "Ag suiteáil an {}…" + +#: bottles/frontend/windows/installer.py:113 +msgid "Performing final checks…" +msgstr "Seiceálacha deiridh á ndéanamh…" + +#: bottles/frontend/windows/installer.py:117 +#, python-brace-format +msgid "Installing {0}…" +msgstr "Ag suiteáil {0}…" + +#: bottles/frontend/windows/installer.py:119 +#, python-brace-format +msgid "{0} is now available in the programs view." +msgstr "Tá {0} ar fáil anois i radharc na gclár." + +#: bottles/frontend/windows/installer.py:166 +msgid "Installer failed with unknown error" +msgstr "Theip ar an suiteálaí le hearráid" + +#: bottles/frontend/windows/launchoptions.py:55 +#, python-brace-format +msgid "{0} is already disabled for this bottle." +msgstr "Tá {0} faoi dhíchumasú cheana féin don bhuidéal seo." + +#: bottles/frontend/windows/launchoptions.py:56 +msgid "This setting is different from the bottle's default." +msgstr "Tá an suíomh seo difriúil ó réamhshocrú an bhuidéil." + +#: bottles/frontend/windows/launchoptions.py:214 +msgid "Select Script" +msgstr "Roghnaigh Script" + +#: bottles/frontend/windows/main_window.py:220 +msgid "Custom Bottles Path not Found" +msgstr "Conair Buidéil Saincheaptha nach bhfuarthas" + +#: bottles/frontend/windows/main_window.py:221 +msgid "" +"Falling back to default path. No bottles from the given path will be listed." +msgstr "" +"Titeamh ar ais go cosán réamhshocraithe. Ní liostófar aon bhuidéil ón gcosán " +"a thugtar." + +#: data/com.usebottles.bottles.desktop.in.in:3 +msgid "@APP_NAME@" +msgstr "@APP_NAME @" + +#: data/com.usebottles.bottles.desktop.in.in:4 +#: data/com.usebottles.bottles.metainfo.xml.in:8 +msgid "Run Windows Software" +msgstr "Rith Bogearraí Windows" + +#: data/com.usebottles.bottles.desktop.in.in:13 +msgid "wine;windows;" +msgstr "fíon; fuinneoga;" + +#: data/com.usebottles.bottles.gschema.xml:6 +msgid "Flatpak migration" +msgstr "Imirce Flatpak" + +#: data/com.usebottles.bottles.gschema.xml:7 +msgid "Toggle the Flatpak migration dialog." +msgstr "Athraigh an dialóg imirce Flatpak." + +#: data/com.usebottles.bottles.gschema.xml:11 +msgid "Dark theme" +msgstr "Téama dorcha" + +#: data/com.usebottles.bottles.gschema.xml:12 +msgid "Force the use of dark theme." +msgstr "Cuir iallach ar úsáid téama dorcha." + +#: data/com.usebottles.bottles.gschema.xml:16 +msgid "Force Offline" +msgstr "Fórsa As Líne" + +#: data/com.usebottles.bottles.gschema.xml:17 +msgid "" +"\"Force disable any network activity even with available network connection." +"\"" +msgstr "" +"\"Díchumasaigh fórsa aon ghníomhaíocht líonra fiú le nasc líonra atá ar fáil." +"\"" + +#: data/com.usebottles.bottles.gschema.xml:21 +msgid "Toggle update date in list" +msgstr "Athraigh dáta nuashonraithe ar an liosta" + +#: data/com.usebottles.bottles.gschema.xml:22 +msgid "Toggle the update date in list of bottles." +msgstr "Athraigh an dáta nuashonraithe i liosta na mbuidéil." + +#: data/com.usebottles.bottles.gschema.xml:26 +msgid "Steam apps listing" +msgstr "Liostú aipeanna Steam" + +#: data/com.usebottles.bottles.gschema.xml:27 +msgid "Toggle steam apps listing." +msgstr "Athraigh liostú aipeanna gaile." + +#: data/com.usebottles.bottles.gschema.xml:31 +msgid "Epic Games listing" +msgstr "Liostú Cluichí Epic" + +#: data/com.usebottles.bottles.gschema.xml:32 +msgid "Toggle epic games listing." +msgstr "Athraigh liostú cluichí eipiciúla." + +#: data/com.usebottles.bottles.gschema.xml:36 +msgid "Ubisoft Connect listing" +msgstr "Liostú Ubisoft Connect" + +#: data/com.usebottles.bottles.gschema.xml:37 +msgid "Toggle ubisoft connect listing." +msgstr "Athraigh liostú ceangail ubisoft." + +#: data/com.usebottles.bottles.gschema.xml:41 +msgid "Window width" +msgstr "Leithead fuinneoige" + +#: data/com.usebottles.bottles.gschema.xml:42 +msgid "Change the window width." +msgstr "Athraigh leithead na fuinneoige." + +#: data/com.usebottles.bottles.gschema.xml:46 +msgid "Window height" +msgstr "Airde fuinneoige" + +#: data/com.usebottles.bottles.gschema.xml:47 +msgid "Change the window height." +msgstr "Athraigh airde na fuinneoige." + +#: data/com.usebottles.bottles.gschema.xml:52 +msgid "Show notifications." +msgstr "Taispeáin fógraí." + +#: data/com.usebottles.bottles.gschema.xml:56 +msgid "Temp cleaning" +msgstr "Glanadh teochta" + +#: data/com.usebottles.bottles.gschema.xml:57 +msgid "Clean the temp path when booting the system." +msgstr "Glan an cosán teochta agus an córas á thosú." + +#: data/com.usebottles.bottles.gschema.xml:61 +msgid "Release Candidate" +msgstr "Scaoil iarrthóir" + +#: data/com.usebottles.bottles.gschema.xml:62 +msgid "Toggle release candidate for runners." +msgstr "Toggle iarrthóir scaoilte do reathaithe." + +#: data/com.usebottles.bottles.gschema.xml:66 +msgid "Startup view" +msgstr "Amharc tosaithe" + +#: data/com.usebottles.bottles.gschema.xml:67 +msgid "Choose which view the application should be started in." +msgstr "Roghnaigh cén radharc ba chóir an t-iarratas a thosú ann." + +#: data/com.usebottles.bottles.gschema.xml:72 +msgid "" +"Toggle experimental features such as versioning and installers. Release " +"candidate for runners." +msgstr "" +"Athraigh gnéithe turgnamhacha mar leagan agus suiteálaithe. Scaoil iarrthóir " +"do reathaithe." + +#: data/com.usebottles.bottles.gschema.xml:76 +msgid "Steam Proton Support" +msgstr "Tacaíocht Prótóin Gaile" + +#: data/com.usebottles.bottles.gschema.xml:77 +msgid "Toggle Steam Proton prefixes support." +msgstr "Toggle Tacaíocht réamhfhoirmeacha Proton Steam." + +#: data/com.usebottles.bottles.gschema.xml:81 +msgid "Experiments:sandbox" +msgstr "Turgnaí:bosca gainimh" + +#: data/com.usebottles.bottles.gschema.xml:82 +msgid "Toggle experimental Sandbox per bottle." +msgstr "Scoránaigh Bosca Gainimh turgnamhach in aghaidh an bhuidéil." + +#: data/com.usebottles.bottles.gschema.xml:86 +msgid "Automatically close Bottles" +msgstr "Buidéil a dhúnadh" + +#: data/com.usebottles.bottles.gschema.xml:87 +msgid "Close Bottles after starting an executable from the file manager." +msgstr "Dún Buidéil tar éis duit infheidhmithe a thosú ón mbainisteoir comhad." + +#: data/com.usebottles.bottles.gschema.xml:91 +msgid "Show sandbox warning" +msgstr "Taispeáin rabhadh bosca gainimh" + +#: data/com.usebottles.bottles.gschema.xml:92 +msgid "Toggle sandbox warning." +msgstr "Athraigh rabhadh bosca gainimh." + +#: data/com.usebottles.bottles.metainfo.xml.in:11 +msgid "" +"Bottles lets you run Windows software on Linux, such as applications and " +"games. It introduces a workflow that helps you organize by categorizing each " +"software to your liking. Bottles provides several tools and integrations to " +"help you manage and optimize your applications." +msgstr "" +"Ligeann Buidéil duit bogearraí Windows a rith ar Linux, mar fheidhmchláir " +"agus cluichí. Tugann sé isteach sreabhadh oibre a chuidíonn leat a eagrú trí " +"gach bogearraí a chatagóiriú de réir mar is maith leat. Soláthraíonn Bottles " +"roinnt uirlisí agus comhtháthú chun cabhrú leat d’fheidhmchláir a bhainistiú " +"agus a bharrfheabhsú." + +#: data/com.usebottles.bottles.metainfo.xml.in:12 +msgid "Features:" +msgstr "Gnéithe:" + +#: data/com.usebottles.bottles.metainfo.xml.in:14 +msgid "Use pre-configured environments as a base" +msgstr "Úsáid timpeallachtaí réamhchumraithe mar bhonn" + +#: data/com.usebottles.bottles.metainfo.xml.in:15 +msgid "Change runners for any bottle" +msgstr "Athraigh reathaithe le haghaidh aon bhuidéal" + +#: data/com.usebottles.bottles.metainfo.xml.in:16 +msgid "Various optimizations and options for gaming" +msgstr "Optamú agus roghanna éagsúla do chearrbhachas" + +#: data/com.usebottles.bottles.metainfo.xml.in:17 +msgid "Repair in case software or bottle is broken" +msgstr "Deisiúchán i gcás go mbeidh bogearraí nó buidéal briste" + +#: data/com.usebottles.bottles.metainfo.xml.in:18 +msgid "Install various known dependencies" +msgstr "Suiteáil spleáchais aitheanta éagsú" + +#: data/com.usebottles.bottles.metainfo.xml.in:19 +msgid "Integrated task manager to manage and monitor processes" +msgstr "Bainisteoir tascanna comhtháite chun próisis a bhainistiú agus" + +#: data/com.usebottles.bottles.metainfo.xml.in:20 +msgid "Backup and restore" +msgstr "Cúltaca agus athshlánú" + +#: data/com.usebottles.bottles.metainfo.xml.in:69 +msgid "Fix runners and components from not showing when prereleases are off" +msgstr "" +"Socraigh reathaithe agus comhpháirteanna gan taispeáint nuair a bhíonn " +"réamheisiúint" + +#: data/com.usebottles.bottles.metainfo.xml.in:70 +msgid "Fix Steam runtime compatibility with Wine runners" +msgstr "Socraigh comhoiriúnacht reatha Steam le reathaithe Fíon" + +#: data/com.usebottles.bottles.metainfo.xml.in:75 +msgid "A few bug fixes" +msgstr "Cúpla socrú fabht" + +#: data/com.usebottles.bottles.metainfo.xml.in:80 +msgid "Support for the double-DLL VKD3D" +msgstr "Tacaíocht don Double-DLL VKD3D" + +#: data/com.usebottles.bottles.metainfo.xml.in:81 +msgid "Updated Flatpak runtime" +msgstr "Rúnam Flatpak nuashonraithe" + +#: data/com.usebottles.bottles.metainfo.xml.in:82 +msgid "Minor improvement and fixes to the library" +msgstr "Mionfheabhsú agus socruithe ar an leabharlann" + +#: data/com.usebottles.bottles.metainfo.xml.in:83 +msgid "Fix the Steam link not being correct" +msgstr "Socraigh an nasc Steam nach bhfuil ceart" + +#: data/com.usebottles.bottles.metainfo.xml.in:84 +msgid "Download stable component by default" +msgstr "Íoslódáil comhpháirt chobhsaí" + +#: data/com.usebottles.bottles.metainfo.xml.in:85 +msgid "Make window remember dimensions" +msgstr "Cuimhnigh ar thoisí fuinneog" + +#: data/com.usebottles.bottles.metainfo.xml.in:90 +msgid "Update metadata information" +msgstr "Faisnéis meiteashonraí a" + +#: data/com.usebottles.bottles.metainfo.xml.in:95 +msgid "Add more update information and correct release notes version" +msgstr "Cuir tuilleadh faisnéise nuashonraithe leis agus an leagan ceart" + +#: data/com.usebottles.bottles.metainfo.xml.in:100 +msgid "Fixed \"Add to Steam\" button" +msgstr "Cnaipe \"Cuir le Steam\" seasta" + +#: data/com.usebottles.bottles.metainfo.xml.in:101 +msgid "Fixed BottleConfig being not serializable" +msgstr "Níl BottleConfig Seasta inshraitheach" + +#: data/com.usebottles.bottles.metainfo.xml.in:102 +msgid "Fixed Patool double extraction failing" +msgstr "Teip ar eastóscadh dúbailte Patool Seasta" + +#: data/com.usebottles.bottles.metainfo.xml.in:107 +msgid "Correct version" +msgstr "Leagan ceart" + +#: data/com.usebottles.bottles.metainfo.xml.in:112 +msgid "Fix crash when creating a bottle" +msgstr "Socraigh timpiste agus buidéal á chruthú" + +#: data/com.usebottles.bottles.metainfo.xml.in:117 +msgid "Major change: Redesign New Bottle interface" +msgstr "Athrú mór: Comhéadan Buidéal Nua a Athdhearadh" + +#: data/com.usebottles.bottles.metainfo.xml.in:118 +msgid "Quality of life improvements:" +msgstr "Feabhsuithe ar cháilíocht na beatha:" + +#: data/com.usebottles.bottles.metainfo.xml.in:120 +msgid "Replace emote-love icon with a library in library page" +msgstr "" +"Cuir deilbhín grá mothúchán in ionad leabharlann i leathanach leabharlainne" + +#: data/com.usebottles.bottles.metainfo.xml.in:121 +msgid "Add toast for \"Run Executable\"" +msgstr "Cuir tósta le haghaidh \"Rith Infheidhmithe\"" + +#: data/com.usebottles.bottles.metainfo.xml.in:123 +msgid "Bug fixes:" +msgstr "Socruithe fabht:" + +#: data/com.usebottles.bottles.metainfo.xml.in:125 +msgid "Adding a shortcut to Steam resulted in an error" +msgstr "Mar thoradh ar aicearra a chur le Steam bhí earráid" + +#: data/com.usebottles.bottles.metainfo.xml.in:126 +msgid "Importing backups resulted an error" +msgstr "Mar thoradh ar chúltacaí a iompórtáil" + +#: data/com.usebottles.bottles.metainfo.xml.in:127 +msgid "Steam Runtime automatically enabled when using wine-ge-custom" +msgstr "Cumasaítear Rúnt-am Gaile go huathoibríoch agus wine-ge-custom á úsáid" + +#: data/com.usebottles.bottles.metainfo.xml.in:128 +msgid "" +"Various library-related fixes, like empty covers, and crashes related to " +"missing entries" +msgstr "" +"Deartuithe éagsúla a bhaineann le leabharlann, cosúil le clúdaigh folamh, " +"agus timpeanna a bhaineann" + +#: data/com.usebottles.bottles.metainfo.xml.in:129 +msgid "Fix various issues related to text encoding" +msgstr "Socraigh saincheisteanna éagsúla a bhaineann le hich" + +#: data/com.usebottles.bottles.metainfo.xml.in:136 +msgid "Fix error when downloading if Bottles isn't run from terminal" +msgstr "Socraigh earráid agus tú ag íoslódáil mura reáchtáiltear Buidéil" + +#: data/com.usebottles.bottles.metainfo.xml.in:143 +msgid "Correct version date" +msgstr "Dáta an leagan ceart" + +#: data/com.usebottles.bottles.metainfo.xml.in:144 +msgid "Hide NVIDIA-related critical errors on non-NVIDIA systems" +msgstr "" +"Folaigh earráidí criticiúla a bhaineann le NVIDIA ar chórais neamh-NVIDIA" + +#: data/com.usebottles.bottles.metainfo.xml.in:151 +msgid "Gamescope improvements and fixes" +msgstr "Feabhsuithe agus socruithe Gamescope" + +#: data/com.usebottles.bottles.metainfo.xml.in:152 +msgid "Dependency installation is faster and more stable" +msgstr "Tá suiteáil spleáchais níos tapúla agus níos cobhsaí" + +#: data/com.usebottles.bottles.metainfo.xml.in:153 +msgid "The health check has more information for faster debugging" +msgstr "Tá tuilleadh faisnéise ag an seiceáil sláinte chun dífhabhtú níos tapa" + +#: data/com.usebottles.bottles.metainfo.xml.in:154 +msgid "NVAPI has a lot of fixes and is more stable, should now work properly" +msgstr "" +"Tá a lán socruithe ag NVAPI agus tá sé níos cobhsaí, ba cheart go n-oibreodh " +"i gceart anois" + +#: data/com.usebottles.bottles.metainfo.xml.in:155 +msgid "Fix crash when downloading a component" +msgstr "Socraigh timpiste agus comhpháirt á íosló" + +#: data/com.usebottles.bottles.metainfo.xml.in:156 +msgid "Backend code improvement by avoiding spin-lock" +msgstr "Feabhsú cód cúltaca trí spin-lock a sheachaint" + +#: data/com.usebottles.bottles.metainfo.xml.in:157 +msgid "More variables for installer scripting" +msgstr "Níos mó athróg le haghaidh scripteála suiteála" + +#: data/com.usebottles.bottles.metainfo.xml.in:158 +msgid "Fix onboard dialog showing \"All ready\" while it was not ready" +msgstr "" +"Socraigh dialóg ar bord a thaispeánann \"Gach réidh\" cé nach raibh sé réidh" + +#: data/com.usebottles.bottles.metainfo.xml.in:159 +msgid "Improvement to build system" +msgstr "Feabhsú chun córas a thógáil" + +#: data/com.usebottles.bottles.metainfo.xml.in:160 +msgid "Enabling VKD3D by default when creating bottles for gaming" +msgstr "" +"Cumasú VKD3D de réir réamhshocraithe agus buidéil á chruthú le haghaidh cear" + +#: data/com.usebottles.bottles.metainfo.xml.in:161 +msgid "Fix crashes when reading Steam files with bad encodings" +msgstr "Déan timpistí a shocrú agus comhaid Steam á léamh le droch-ionchódaithe" + +#: data/com.usebottles.bottles.metainfo.xml.in:162 +msgid "" +"Fix components not updated correctly in the UI after installation/" +"uninstallation" +msgstr "" +"Socraigh comhpháirteanna nach bhfuil nuashonraithe i gceart sa Chomhéadan " +"tar éis suiteál" + +#: data/com.usebottles.bottles.metainfo.xml.in:163 +msgid "More FSR fixes" +msgstr "Tuilleadh socruithe FSR" + +#: data/com.usebottles.bottles.metainfo.xml.in:164 +msgid "" +"Fix the issue when a program closes after it was launched from \"Run " +"executable\"" +msgstr "" +"Socraigh an cheist nuair a dhúnann clár tar éis é a sheoladh ó \"Rith " +"infheidhmithe\"" + +#: data/com.usebottles.bottles.metainfo.xml.in:165 +msgid "and many, many, many more!" +msgstr "agus go leor, go leor, go leor eile!" diff --git a/po/he.po b/po/he.po index d0a2461a97e..d0d33705318 100644 --- a/po/he.po +++ b/po/he.po @@ -22,25 +22,25 @@ msgstr "" #: bottles/backend/managers/backup.py:48 bottles/backend/managers/backup.py:95 msgid "No path specified" -msgstr "מיקום לא נבחר" +msgstr "לא נבחר נתיב" #: bottles/backend/managers/backup.py:56 #, python-brace-format msgid "Backup {0}" -msgstr "" +msgstr "גיבוי {0}" #: bottles/backend/managers/backup.py:101 #, python-brace-format msgid "Importing backup: {0}" -msgstr "" +msgstr "גיבוי מיובא: {0}" #: bottles/backend/managers/manager.py:1057 msgid "Fail to install components, tried 3 times." -msgstr "נכשל להתקין תוספים, לאחר 3 נסיונות." +msgstr "התקנת תוספים נכשלה, לאחר 3 נסיונות." #: bottles/backend/managers/manager.py:1068 msgid "Missing essential components. Installing…" -msgstr "תוספים בסיסיים חסרים, מתקין…" +msgstr "תוספים בסיסיים חסרים, מותקנים…" #: bottles/backend/managers/manager.py:1145 msgid "Failed to create bottle directory." @@ -52,24 +52,24 @@ msgstr "" #: bottles/backend/managers/manager.py:1162 msgid "Generating bottle configuration…" -msgstr "מייצר הגדרות בקבוק…" +msgstr "הגדרות בקבוק נוצרות…" #: bottles/backend/managers/manager.py:1185 msgid "Template found, applying…" -msgstr "" +msgstr "נמצאה תבנית, מיושמת…" #. execute wineboot on the bottle path #: bottles/backend/managers/manager.py:1197 msgid "The Wine config is being updated…" -msgstr "" +msgstr "הגדרות WINE מתעדכנות כעת…" #: bottles/backend/managers/manager.py:1199 msgid "Wine config updated!" -msgstr "" +msgstr "הצלחנו לעדכן את ההגדרות של WINE!" #: bottles/backend/managers/manager.py:1207 msgid "Running as Flatpak, sandboxing userdir…" -msgstr "" +msgstr "הרצה כ-FLATPAK, בתהליך בידוד ...USERDIR" #: bottles/backend/managers/manager.py:1209 msgid "Sandboxing userdir…" @@ -81,346 +81,350 @@ msgstr "מגדיר גרסת ווינדוס…" #: bottles/backend/managers/manager.py:1260 msgid "Apply CMD default settings…" -msgstr "" +msgstr "יישום הגדרות ברירת-מחדל ל-CMD" #: bottles/backend/managers/manager.py:1268 msgid "Optimizing environment…" -msgstr "" +msgstr "ממטבים את הסביבה…" #: bottles/backend/managers/manager.py:1279 #, python-brace-format msgid "Applying environment: {0}…" -msgstr "" +msgstr "מיישמים סביבה: {0}…" #: bottles/backend/managers/manager.py:1289 msgid "(!) Using a custom environment recipe…" -msgstr "" +msgstr "נא לשים לב (!) נעשה שימוש במתכון מותאם-אישית ליצירת הסביבה…" #: bottles/backend/managers/manager.py:1292 msgid "(!) Recipe not not found or not valid…" -msgstr "" +msgstr "אבוי (!) לא מצאנו את המתכון, או שהוא פגום…" #: bottles/backend/managers/manager.py:1309 msgid "Installing DXVK…" -msgstr "" +msgstr "מתקינים את DXVK…" #: bottles/backend/managers/manager.py:1317 msgid "Installing VKD3D…" -msgstr "" +msgstr "מתקינים את VKD3D…" #: bottles/backend/managers/manager.py:1326 msgid "Installing DXVK-NVAPI…" -msgstr "" +msgstr "מתקינים את DXVK-NVAPI…" #: bottles/backend/managers/manager.py:1335 #, python-format msgid "Installing dependency: %s …" -msgstr "" +msgstr "מתקינים חבילות-תלות: %s …" #: bottles/backend/managers/manager.py:1345 msgid "Creating versioning state 0…" -msgstr "" +msgstr "יוצרים גרסאות מצב 0…" #: bottles/backend/managers/manager.py:1353 msgid "Finalizing…" -msgstr "" +msgstr "עוד רגע מסיימים :)" #: bottles/backend/managers/manager.py:1364 msgid "Caching template…" -msgstr "" +msgstr "טומנים את התבנית…" #: bottles/backend/managers/versioning.py:83 msgid "Committing state …" -msgstr "" +msgstr "מקבעים מצב…" #: bottles/backend/managers/versioning.py:90 msgid "Nothing to commit" -msgstr "" +msgstr "אין מה לקבע!" #: bottles/backend/managers/versioning.py:96 #, python-brace-format msgid "New state [{0}] created successfully!" -msgstr "" +msgstr "יצרנו מצב חדש {0} כהלכה!" #: bottles/backend/managers/versioning.py:123 msgid "States list retrieved successfully!" -msgstr "" +msgstr "השגנו את רשומות המצבים!" #: bottles/backend/managers/versioning.py:153 #, python-brace-format msgid "State {0} restored successfully!" -msgstr "" +msgstr "שחזרנו למצב {0} כהלכה!" #: bottles/backend/managers/versioning.py:155 msgid "Restoring state {} …" -msgstr "" +msgstr "משחזרים מצב {} …" #: bottles/backend/managers/versioning.py:162 msgid "State not found" -msgstr "" +msgstr "לא מצאנו את המצב *-*" #: bottles/backend/managers/versioning.py:168 msgid "State {} is already the active state" -msgstr "" +msgstr "זה כבר המצב {} העדכני ביותר!" #: bottles/frontend/main.py:112 msgid "Show version" -msgstr "" +msgstr "הצגת גרסה" #: bottles/frontend/main.py:120 msgid "Executable path" -msgstr "" +msgstr "נתיב לקובץ ההרצה \\ האצווה" #: bottles/frontend/main.py:128 msgid "lnk path" -msgstr "" +msgstr "נתיב דיו" #: bottles/frontend/main.py:136 bottles/frontend/ui/library-entry.blp:118 #: bottles/frontend/ui/list-entry.blp:5 msgid "Bottle name" -msgstr "" +msgstr "כינוי הבקבוק" #: bottles/frontend/main.py:144 msgid "Pass arguments" -msgstr "" +msgstr "העברת פרמטר" #: bottles/frontend/main.py:203 msgid "Invalid URI (syntax: bottles:run//)" -msgstr "" +msgstr "URI שגוי! (תחביר: bottles:run//)" #: bottles/frontend/main.py:244 msgid "[Quit] request received." -msgstr "" +msgstr "בקשת [יציאה] נתקבלה" #: bottles/frontend/main.py:253 msgid "[Help] request received." -msgstr "" +msgstr "בקשת [סיוע] נתקבלה." #: bottles/frontend/main.py:261 msgid "[Refresh] request received." -msgstr "" +msgstr "בקשת [רענון] נתקבלה." #: bottles/frontend/main.py:294 msgid "Donate" -msgstr "" +msgstr "תרומה" #: bottles/frontend/main.py:299 msgid "Third-Party Libraries and Special Thanks" -msgstr "" +msgstr "תודות מיוחדות, ספריות צד-ג'" #: bottles/frontend/main.py:325 msgid "Sponsored and Funded by" -msgstr "" +msgstr "מקודם וממומן ע\"י" # Translators: Bottles is a proper noun referring to the app #: bottles/frontend/ui/about.blp:5 msgid "Copyright © 2017 Bottles Developers" -msgstr "" +msgstr "כל הזכויות שמורות © 2017 Bottles Developers" # Translators: Bottles is a proper noun referring to the app #: bottles/frontend/ui/about.blp:10 msgid "Bottles Developers" -msgstr "" +msgstr "מפתחי Bottles" #: bottles/frontend/ui/about.blp:12 msgid "translator_credits" -msgstr "" +msgstr "תודות_מתרגמים" #: bottles/frontend/ui/component-entry.blp:4 msgid "Component version" -msgstr "" +msgstr "גרסת רכיבים" #: bottles/frontend/ui/component-entry.blp:12 #: bottles/frontend/ui/dependency-entry.blp:29 #: bottles/frontend/ui/program-entry.blp:77 msgid "Uninstall" -msgstr "" +msgstr "הסרת התקנה" #: bottles/frontend/ui/component-entry.blp:23 msgid "Browse Files" -msgstr "" +msgstr "עיון בקבצים" #: bottles/frontend/ui/component-entry.blp:34 msgid "" "The installation failed. This may be due to a repository error, partial " "download or checksum mismatch. Press to try again." msgstr "" +"אבוי, ההתקנה כשלה! יש סיכוי שהגענו למצב זה בשל שגיאת ארכיב, הורדה פגומה או " +"קושי באימות. כדאי לנסות שוב ;)" #: bottles/frontend/ui/component-entry.blp:45 msgid "Download & Install" -msgstr "" +msgstr "הורדה והתקנה" #: bottles/frontend/ui/component-entry.blp:58 msgid "0%" -msgstr "" +msgstr "0%" #: bottles/frontend/ui/dependency-entry.blp:16 msgid "Show Manifest" -msgstr "" +msgstr "הצגת מצהר" #: bottles/frontend/ui/dependency-entry.blp:20 msgid "License" -msgstr "" +msgstr "רשיון" #: bottles/frontend/ui/dependency-entry.blp:24 msgid "Reinstall" -msgstr "" +msgstr "התקנה חוזרת" #: bottles/frontend/ui/dependency-entry.blp:36 #: bottles/frontend/ui/installer-entry.blp:27 msgid "Report a Bug…" -msgstr "" +msgstr "דיווח על תֶּקֶל…" #: bottles/frontend/ui/dependency-entry.blp:42 msgid "Dependency name" -msgstr "" +msgstr "שם חבילת-תלות" #: bottles/frontend/ui/dependency-entry.blp:44 msgid "Dependency description" -msgstr "" +msgstr "תיאור חבילת-תלות" #: bottles/frontend/ui/dependency-entry.blp:51 msgid "Category" -msgstr "" +msgstr "סוגה" #: bottles/frontend/ui/dependency-entry.blp:64 msgid "Download & Install this Dependency" -msgstr "" +msgstr "הורדה והתקנת חבילת-תלות" #: bottles/frontend/ui/dependency-entry.blp:79 msgid "" "An installation error occurred. Restart Bottles to read the Crash Report or " "run it via terminal to read the output." msgstr "" +"אבוי, תקלת התקנה התרחשה. אפשר לאתחל את Bottles כדי לחזות בדו\"ח הקריסה או " +"להריצו במסוף כדי לקרוא את הפלט" #: bottles/frontend/ui/dependency-entry.blp:93 msgid "Dependency Menu" -msgstr "" +msgstr "תפריט תלויות" #: bottles/frontend/ui/details-bottle.blp:16 msgid "Troubleshooting" -msgstr "" +msgstr "ניפוי תקלות" #: bottles/frontend/ui/details-bottle.blp:24 msgid "Browse Files…" -msgstr "" +msgstr "עיון בקבצים…" #: bottles/frontend/ui/details-bottle.blp:28 msgid "Duplicate Bottle…" -msgstr "" +msgstr "שכפול בקבוק…" #: bottles/frontend/ui/details-bottle.blp:32 #: bottles/frontend/ui/importer.blp:73 msgid "This is the complete archive of your bottle, including personal files." -msgstr "" +msgstr "זהו ארכוב מלא של בקבוקך, הכולל בתוכו גם קבצים אישיים." #: bottles/frontend/ui/details-bottle.blp:33 msgid "Full Backup…" -msgstr "" +msgstr "גיבוי מלא…" #: bottles/frontend/ui/details-bottle.blp:37 #: bottles/frontend/ui/importer.blp:68 msgid "" "This is just the bottle configuration, it's perfect if you want to create a " "new one but without personal files." -msgstr "" +msgstr "מכיל רק את הגדרת הבקבוק, מושלם ליצירת אחד חדש, בלי קבצים אישיים." #: bottles/frontend/ui/details-bottle.blp:38 msgid "Export Configuration…" -msgstr "" +msgstr "ייצוא הגדרות…" #: bottles/frontend/ui/details-bottle.blp:45 #: bottles/frontend/views/bottle_details.py:344 msgid "Show Hidden Programs" -msgstr "" +msgstr "הצגת תוכניות נסתרות" #: bottles/frontend/ui/details-bottle.blp:49 msgid "Search for new programs" -msgstr "" +msgstr "חיפוש אחר תוכנות חדשות" #: bottles/frontend/ui/details-bottle.blp:56 msgid "Delete Bottle…" -msgstr "" +msgstr "מחיקת בקבוק…" #: bottles/frontend/ui/details-bottle.blp:73 #: bottles/frontend/ui/details-dependencies.blp:99 #: bottles/frontend/ui/details-installers.blp:68 msgid "Secondary Menu" -msgstr "" +msgstr "תפריט משני" #: bottles/frontend/ui/details-bottle.blp:90 msgid "Force Stop all Processes" -msgstr "" +msgstr "עצירה מלאה וכפוייה של כל התהליכים הפעילים" #: bottles/frontend/ui/details-bottle.blp:94 msgid "Simulate a Windows system shutdown." -msgstr "" +msgstr "דימוי כיבוי מלא של מערכת WINDOWS." #: bottles/frontend/ui/details-bottle.blp:95 msgid "Shutdown" -msgstr "" +msgstr "כיבוי" #: bottles/frontend/ui/details-bottle.blp:99 msgid "Simulate a Windows system reboot." -msgstr "" +msgstr "דימוי הפעלה מחדש של מערכת WINDOWS." #: bottles/frontend/ui/details-bottle.blp:100 msgid "Reboot" -msgstr "" +msgstr "הפעלה מחדש" #: bottles/frontend/ui/details-bottle.blp:118 #: bottles/frontend/ui/dialog-launch-options.blp:6 msgid "Launch Options" -msgstr "" +msgstr "אפשרויות הרצה" #: bottles/frontend/ui/details-bottle.blp:135 msgid "Run in Terminal" -msgstr "" +msgstr "הרצה במסוף" #: bottles/frontend/ui/details-bottle.blp:148 msgid "Drop files to execute them" -msgstr "" +msgstr "גררו לכאן קבצים, ונריץ אותם." #: bottles/frontend/ui/details-bottle.blp:164 msgid "My bottle" -msgstr "" +msgstr "הבקבוק שלי" #: bottles/frontend/ui/details-bottle.blp:177 msgid "Win64" -msgstr "" +msgstr "Win64" #: bottles/frontend/ui/details-bottle.blp:189 #: bottles/frontend/ui/list-entry.blp:12 bottles/frontend/ui/new.blp:71 msgid "Environment" -msgstr "" +msgstr "סביבה" #: bottles/frontend/ui/details-bottle.blp:201 #: bottles/frontend/ui/details-preferences.blp:14 #: bottles/frontend/ui/new.blp:128 msgid "Runner" -msgstr "" +msgstr "מריץ" #: bottles/frontend/ui/details-bottle.blp:213 #: bottles/frontend/ui/list-entry.blp:21 msgid "Versioning enabled for this bottle" -msgstr "" +msgstr "רשומת גרסאות זמינה עבור הבקבוק" #: bottles/frontend/ui/details-bottle.blp:218 msgid "Versioning is active for this bottle." -msgstr "" +msgstr "רשומת גרסאות פעילה עבור הבקבוק" #: bottles/frontend/ui/details-bottle.blp:227 #: bottles/frontend/ui/list-entry.blp:31 msgid "0" -msgstr "" +msgstr "0" #: bottles/frontend/ui/details-bottle.blp:247 msgid "Run Executable…" -msgstr "" +msgstr "הרצת קובץ הרצה…" #: bottles/frontend/ui/details-bottle.blp:272 msgid "Programs" -msgstr "" +msgstr "תכונות" #: bottles/frontend/ui/details-bottle.blp:275 msgid "" @@ -428,115 +432,119 @@ msgid "" "executable to the Programs list, or \"Install Programs…\" to install " "programs curated by the community." msgstr "" +"על מנת להריץ קבצי הרצה, נקיש על \"הרצת קובץ הרצה...\", \"הוספת קיצור דרך\" " +"כדי להוסיף תוכנה לרשומת התוכנות, או \"התקנת תוכנות\" על מנת להתקין תוכנות " +"קהילתיות." #: bottles/frontend/ui/details-bottle.blp:298 msgid "Add Shortcuts…" -msgstr "" +msgstr "הוספת קיצורי דרך…" #: bottles/frontend/ui/details-bottle.blp:325 msgid "Install Programs…" -msgstr "" +msgstr "התקנת תוכנות…" #: bottles/frontend/ui/details-bottle.blp:346 msgid "Options" -msgstr "" +msgstr "אפשרויות" #: bottles/frontend/ui/details-bottle.blp:350 #: bottles/frontend/views/details.py:141 msgid "Settings" -msgstr "" +msgstr "הגדרות" #: bottles/frontend/ui/details-bottle.blp:351 msgid "Configure bottle settings." -msgstr "" +msgstr "הגדרת בקבוק." #: bottles/frontend/ui/details-bottle.blp:360 #: bottles/frontend/views/details.py:145 msgid "Dependencies" -msgstr "" +msgstr "חבילות-תלות" #: bottles/frontend/ui/details-bottle.blp:361 msgid "Install dependencies for programs." -msgstr "" +msgstr "התקנת חבילות-תלות עבור תוכנות" #: bottles/frontend/ui/details-bottle.blp:370 #: bottles/frontend/ui/details-preferences.blp:377 #: bottles/frontend/views/details.py:149 msgid "Snapshots" -msgstr "" +msgstr "תמונות מצב" #: bottles/frontend/ui/details-bottle.blp:371 msgid "Create and manage bottle states." -msgstr "" +msgstr "יצירה וניהול מצבי בקבוקים." #: bottles/frontend/ui/details-bottle.blp:380 #: bottles/frontend/ui/details-bottle.blp:426 #: bottles/frontend/views/details.py:157 msgid "Task Manager" -msgstr "" +msgstr "מנהל תהליכים" #: bottles/frontend/ui/details-bottle.blp:381 msgid "Manage running programs." -msgstr "" +msgstr "ניהול תוכנות פעילות" #: bottles/frontend/ui/details-bottle.blp:390 msgid "Tools" -msgstr "" +msgstr "כלים" #: bottles/frontend/ui/details-bottle.blp:394 msgid "Command Line" -msgstr "" +msgstr "שורת פקודה" #: bottles/frontend/ui/details-bottle.blp:395 msgid "Run commands inside the Bottle." -msgstr "" +msgstr "הרצת פקודות בתוך הבקבוק" #: bottles/frontend/ui/details-bottle.blp:404 msgid "Registry Editor" -msgstr "" +msgstr "עורך מרשמה" #: bottles/frontend/ui/details-bottle.blp:405 msgid "Edit the internal registry." -msgstr "" +msgstr "עריכת המרשמה הפנימית" #: bottles/frontend/ui/details-bottle.blp:413 msgid "Legacy Wine Tools" -msgstr "" +msgstr "כלי עבר WINE" #: bottles/frontend/ui/details-bottle.blp:417 msgid "Explorer" -msgstr "" +msgstr "סייר" #: bottles/frontend/ui/details-bottle.blp:435 msgid "Debugger" -msgstr "" +msgstr "מנפה" #: bottles/frontend/ui/details-bottle.blp:444 #: bottles/frontend/ui/importer.blp:69 bottles/frontend/ui/new.blp:145 msgid "Configuration" -msgstr "" +msgstr "תצורה" #: bottles/frontend/ui/details-bottle.blp:453 msgid "Uninstaller" -msgstr "" +msgstr "תוכנת הסרת ההתקנה" #: bottles/frontend/ui/details-bottle.blp:462 msgid "Control Panel" -msgstr "" +msgstr "לוח הבקרה" #: bottles/frontend/ui/details-dependencies.blp:9 msgid "Search for dependencies…" -msgstr "" +msgstr "חיפוש אחר חבילות-תלות…" #: bottles/frontend/ui/details-dependencies.blp:22 #: bottles/frontend/ui/preferences.blp:178 #: bottles/frontend/ui/preferences.blp:235 +#, fuzzy msgid "You're offline :(" -msgstr "" +msgstr "איפה האינטרנט?!" #: bottles/frontend/ui/details-dependencies.blp:25 msgid "Bottles is running in offline mode, so dependencies are not available." -msgstr "" +msgstr "הבקבוק פועל במצב לא-מקוון, לכן חבילות-תלות לא תהיינה זמינות" #: bottles/frontend/ui/details-dependencies.blp:47 msgid "" @@ -545,34 +553,38 @@ msgid "" "Files on this page are provided by third parties under a proprietary " "license. By installing them, you agree with their respective licensing terms." msgstr "" +"חבילות-תלות הינם משאבים המשפרים את התאימות של תוכנות WINDOWS.\n" +"\n" +"קבצים בעמוד זה מובאים לפניכם בידי צדדי-ג' תחת רישיון קנייני. על ידי התקנתם, " +"הנכם מסכימים לתנאי רישויים." #: bottles/frontend/ui/details-dependencies.blp:76 msgid "Report a problem or a missing dependency." -msgstr "" +msgstr "דיווח על בעיה או חבילת-תלות חסרה" #: bottles/frontend/ui/details-dependencies.blp:77 msgid "Report Missing Dependency" -msgstr "" +msgstr "דיווח על חבילת-תלות חסרה" #: bottles/frontend/ui/details-dependencies.blp:81 msgid "Read Documentation." -msgstr "" +msgstr "קריאת תיעוד-עזר" #: bottles/frontend/ui/details-dependencies.blp:82 #: bottles/frontend/ui/details-installers.blp:51 #: bottles/frontend/ui/details-versioning.blp:37 msgid "Documentation" -msgstr "" +msgstr "תיעוד-עזר" #: bottles/frontend/ui/details-dependencies.blp:92 #: bottles/frontend/ui/details-installers.blp:61 #: bottles/frontend/ui/window.blp:46 msgid "Search" -msgstr "" +msgstr "חיפוש" #: bottles/frontend/ui/details-installers.blp:9 msgid "Search for Programs…" -msgstr "" +msgstr "חיפוש תוכנות…" #: bottles/frontend/ui/details-installers.blp:15 msgid "" @@ -581,44 +593,48 @@ msgid "" "Files on this page are provided by third parties under a proprietary " "license. By installing them, you agree with their respective licensing terms." msgstr "" +"התקנת תוכנות קהילתיות.\n" +"\n" +"הקבצים בעמוד זה מובאים לפניכם בידי צדדי-ג' תחת רישיון קנייני. על ידי התקנתם, " +"הנכם מסכימים לתנאי רישויים." #: bottles/frontend/ui/details-installers.blp:29 msgid "No Installers Found" -msgstr "" +msgstr "לא מצאנו תוכנות התקנה *-*" #: bottles/frontend/ui/details-installers.blp:32 msgid "" "The repository is unreachable or no installer is compatible with this bottle." -msgstr "" +msgstr "הארכיב לא זמין כרגע או שאין מתקין הנתמך בידי הבקבוק" #: bottles/frontend/ui/details-installers.blp:50 #: bottles/frontend/ui/details-versioning.blp:36 #: bottles/frontend/ui/preferences.blp:81 msgid "Read Documentation" -msgstr "" +msgstr "קריאת תיעוד-עזר" #: bottles/frontend/ui/details-preferences.blp:6 #: bottles/frontend/ui/dialog-duplicate.blp:52 msgid "Name" -msgstr "" +msgstr "שם" #: bottles/frontend/ui/details-preferences.blp:11 msgid "Components" -msgstr "" +msgstr "רכיבים" #: bottles/frontend/ui/details-preferences.blp:15 #: bottles/frontend/ui/new.blp:129 msgid "The version of the Wine compatibility layer." -msgstr "" +msgstr "גרסאת שכבת התאימות WINE." #: bottles/frontend/ui/details-preferences.blp:17 msgid "Updating Runner and components, please wait…" -msgstr "" +msgstr "מעדכן את המריץ ועוד שלל רכיבים פנימיים, רק רגע…" #: bottles/frontend/ui/details-preferences.blp:27 #: bottles/frontend/ui/preferences.blp:262 msgid "DXVK" -msgstr "" +msgstr "DXVK" #: bottles/frontend/ui/details-preferences.blp:28 msgid "Improve Direct3D 8/9/10/11 compatibility by translating it to Vulkan." @@ -626,127 +642,132 @@ msgstr "" #: bottles/frontend/ui/details-preferences.blp:30 msgid "Updating DXVK, please wait…" -msgstr "" +msgstr "מעדכנים את DXVK, רק עוד רגע…" #: bottles/frontend/ui/details-preferences.blp:40 #: bottles/frontend/ui/preferences.blp:266 msgid "VKD3D" -msgstr "" +msgstr "VKD3D" #: bottles/frontend/ui/details-preferences.blp:41 msgid "Improve Direct3D 12 compatibility by translating it to Vulkan." -msgstr "" +msgstr "שיפור תאימות Direct3D 12 ע\"י תרגום ל- Vulkan." #: bottles/frontend/ui/details-preferences.blp:43 msgid "Updating VKD3D, please wait…" -msgstr "" +msgstr "מעדכנים את VKD3D, רק עוד רגע…" #: bottles/frontend/ui/details-preferences.blp:54 msgid "DXVK NVAPI" -msgstr "" +msgstr "DXVK NVAPI" #: bottles/frontend/ui/details-preferences.blp:58 #: bottles/frontend/ui/details-preferences.blp:93 msgid "Updating DXVK-NVAPI, please wait…" -msgstr "" +msgstr "מעדכנים את DXVK-NVAPI, רק עוד רגע…" #: bottles/frontend/ui/details-preferences.blp:68 #: bottles/frontend/ui/preferences.blp:274 msgid "LatencyFleX" -msgstr "" +msgstr "LatencyFleX" #: bottles/frontend/ui/details-preferences.blp:69 msgid "Increase responsiveness. Can be detected by some anti-cheat software." -msgstr "" +msgstr "משפר תגובתיות, ניתן לזיהוי על-ידי תוכנות מניעת רמאויות מסויימות." #: bottles/frontend/ui/details-preferences.blp:71 msgid "Updating LatencyFleX, please wait…" -msgstr "" +msgstr "מעדכנים את LatencyFleX, רק עוד רגע…" #: bottles/frontend/ui/details-preferences.blp:84 msgid "Display" -msgstr "" +msgstr "מסך" #: bottles/frontend/ui/details-preferences.blp:88 msgid "Deep Learning Super Sampling" -msgstr "" +msgstr "למידה מעמיקה עם דיגום מורחב" #: bottles/frontend/ui/details-preferences.blp:89 msgid "" "Increase performance at the expense of visuals using DXVK-NVAPI. Only works " "on newer NVIDIA GPUs." msgstr "" +"שיפור הביצועים הכרוך בפיחות גרפי תוך שימוש ב- DXVK-NVAPI. זמין אך ורק ברכיבי " +"NVIDIA חדשים יותר." #: bottles/frontend/ui/details-preferences.blp:105 msgid "FidelityFX Super Resolution" -msgstr "" +msgstr "FidelityFX רזולוציה משופרת" #: bottles/frontend/ui/details-preferences.blp:106 msgid "Increase performance at the expense of visuals. Only works on Vulkan." -msgstr "" +msgstr "שיפור הביצועים במחיר פיחות הגרפיקה. זמין אך ורק ב-Vulkan." #: bottles/frontend/ui/details-preferences.blp:108 msgid "Manage FidelityFX Super Resolution settings" -msgstr "" +msgstr "ניהול והגדרת רזולוציה משופרת FidelityFX" #: bottles/frontend/ui/details-preferences.blp:125 msgid "Discrete Graphics" -msgstr "" +msgstr "גרפיקה בדידים" #: bottles/frontend/ui/details-preferences.blp:126 msgid "" "Use the discrete graphics card to increase performance at the expense of " "power consumption." msgstr "" +"השימוש בגרפיקה בבדידים מועיל כאשר מעוניינים לשפר ביצועים, במחיר צריכת חשמל " +"מוגברת" #: bottles/frontend/ui/details-preferences.blp:135 msgid "Post-Processing Effects" -msgstr "" +msgstr "אפקטים לאחר-העיבוד" #: bottles/frontend/ui/details-preferences.blp:136 msgid "" "Add various post-processing effects using vkBasalt. Only works on Vulkan." msgstr "" +"הוספת מיני אפקטים לאחר-העיבוד תוך שימש ב- vkBasalt. זמין אך ורק ב- Vulkan." #: bottles/frontend/ui/details-preferences.blp:138 msgid "Manage Post-Processing Layer settings" -msgstr "" +msgstr "הגדרה וניהול של שכבות שלאחר-העיבוד" #: bottles/frontend/ui/details-preferences.blp:154 msgid "Manage how games should be displayed on the screen using Gamescope." -msgstr "" +msgstr "ניהול כיצד משחקים יוצגו על המסך, תוך שימוש ב- Gamescope." #: bottles/frontend/ui/details-preferences.blp:157 msgid "Manage Gamescope settings" -msgstr "" +msgstr "ניהול הגדרות תצורה ל-Gamescope." #: bottles/frontend/ui/details-preferences.blp:171 msgid "Advanced Display Settings" -msgstr "" +msgstr "הגדרות תצוגה מורחבות." #: bottles/frontend/ui/details-preferences.blp:184 msgid "Performance" -msgstr "" +msgstr "ביצועים" #: bottles/frontend/ui/details-preferences.blp:188 msgid "Enable synchronization to increase performance of multicore processors." -msgstr "" +msgstr "הפעלת הסנכרון, כך שהביצועים ישופרו במעבדים בעלי מספר ליבות." #: bottles/frontend/ui/details-preferences.blp:189 msgid "Synchronization" -msgstr "" +msgstr "סנכרון" #: bottles/frontend/ui/details-preferences.blp:193 msgid "System" -msgstr "" +msgstr "מערכת" #: bottles/frontend/ui/details-preferences.blp:194 msgid "Esync" -msgstr "" +msgstr "Esync" #: bottles/frontend/ui/details-preferences.blp:195 msgid "Fsync" -msgstr "" +msgstr "Fsync" #: bottles/frontend/ui/details-preferences.blp:196 msgid "Futex2" @@ -754,102 +775,111 @@ msgstr "" #: bottles/frontend/ui/details-preferences.blp:202 msgid "Monitor Performance" -msgstr "" +msgstr "ביצועי המסך" #: bottles/frontend/ui/details-preferences.blp:203 msgid "" "Display monitoring information such as framerate, temperatures, CPU/GPU load " "and more on OpenGL and Vulkan using MangoHud." msgstr "" +"הצגת מידע סטטיסטי (קצב רענון, מעלות, עומס על המעבדים ושלל רכיבים נוספים) על " +"גבי OpenGL ו-Vulkan תוך שימוש ב- MangoHud." #: bottles/frontend/ui/details-preferences.blp:211 msgid "Feral GameMode" -msgstr "" +msgstr "Feral GameMode" #: bottles/frontend/ui/details-preferences.blp:212 msgid "" "Apply a set of optimizations to your device. Can improve game performance." -msgstr "" +msgstr "מיישם סדרת שיפורים וביצועים למכשירך, עשוי לשפר ביצועים." #: bottles/frontend/ui/details-preferences.blp:221 msgid "Preload Game Files" -msgstr "" +msgstr "טעינה מוקדמת של קבצי משחק" #: bottles/frontend/ui/details-preferences.blp:222 msgid "" "Improve loading time when launching the game multiple times. The game will " "take longer to start for the first time." msgstr "" +"שיפור זמן הטעינה בעת הפעלת המשחק מספר פעמים, אך ההפעלה הראשונית תארך זמן רב " +"יותר." #: bottles/frontend/ui/details-preferences.blp:226 msgid "Manage vmtouch settings" -msgstr "" +msgstr "ניהול הגדרות vmtouch" #: bottles/frontend/ui/details-preferences.blp:241 msgid "OBS Game Capture" -msgstr "" +msgstr "לכידת משחק עם OBS" #: bottles/frontend/ui/details-preferences.blp:242 msgid "Toggle OBS Game Capture for all Vulkan and OpenGL programs." -msgstr "" +msgstr "הפעלת לכידת משחק עם OBS לכל יישומי vulkan ו- OpenGL." #: bottles/frontend/ui/details-preferences.blp:251 msgid "Compatibility" -msgstr "" +msgstr "תאימות" #: bottles/frontend/ui/details-preferences.blp:254 msgid "Windows Version" -msgstr "" +msgstr "גרסת ווינדוס" #: bottles/frontend/ui/details-preferences.blp:257 +#, fuzzy msgid "Updating Windows version, please wait…" -msgstr "" +msgstr "מעדכנים את גרסת ה- ווינדוס, רק עוד רגע…" #: bottles/frontend/ui/details-preferences.blp:266 msgid "Language" -msgstr "" +msgstr "שפה" #: bottles/frontend/ui/details-preferences.blp:267 msgid "Choose the language to use with programs." -msgstr "" +msgstr "בחירת השפה לשימוש עם יישומים ותוכנות." #: bottles/frontend/ui/details-preferences.blp:275 msgid "Dedicated Sandbox" -msgstr "" +msgstr "\"ארגז חול\" ייעודי" #: bottles/frontend/ui/details-preferences.blp:276 msgid "Use a restricted/managed environment for this bottle." -msgstr "" +msgstr "שימוש בסביבה מוגבלת\\מנוהלת עבור הבקבוק." #: bottles/frontend/ui/details-preferences.blp:279 msgid "Manage the Sandbox Permissions" -msgstr "" +msgstr "ניהול הרשאות \"ארגז החול\"" # Translators: Bottles is a proper noun referring to the app #: bottles/frontend/ui/details-preferences.blp:295 msgid "Bottles Runtime" -msgstr "" +msgstr "סביבת הרצה עבור הבקבוק" #: bottles/frontend/ui/details-preferences.blp:296 msgid "" "Provide a bundle of extra libraries for more compatibility. Disable it if " "you run into issues." msgstr "" +"אספקת מקבץ של ספריות נוספות לשיפור התאימות. אם יש בעיות אז כדאי לבטל את " +"הבחירה." #: bottles/frontend/ui/details-preferences.blp:306 msgid "Steam Runtime" -msgstr "" +msgstr "הרצת Steam" #: bottles/frontend/ui/details-preferences.blp:307 msgid "" "Provide a bundle of extra libraries for more compatibility with Steam games. " "Disable it if you run into issues." msgstr "" +"אספקת ספריות נוספות לשיפור התאימות עם משחקי Steam. אם יש בעיות אז כדאי לבטל " +"את הבחירה." #: bottles/frontend/ui/details-preferences.blp:315 #: bottles/frontend/ui/dialog-launch-options.blp:83 msgid "Working Directory" -msgstr "" +msgstr "נתיב לרשומת פעילות" #: bottles/frontend/ui/details-preferences.blp:318 #: bottles/frontend/ui/dialog-launch-options.blp:59 @@ -857,28 +887,28 @@ msgstr "" #: bottles/frontend/ui/new.blp:150 bottles/frontend/ui/new.blp:181 #: bottles/frontend/ui/preferences.blp:136 msgid "Reset to Default" -msgstr "" +msgstr "שחזור להגדרות ברירת-מחדל" #: bottles/frontend/ui/details-preferences.blp:339 #: bottles/frontend/ui/preferences.blp:157 bottles/frontend/views/new.py:78 #: bottles/frontend/views/preferences.py:210 msgid "(Default)" -msgstr "" +msgstr "(ברירת-מחדל)" #: bottles/frontend/ui/details-preferences.blp:347 #: bottles/frontend/ui/dialog-dll-overrides.blp:7 #: bottles/frontend/ui/dialog-dll-overrides.blp:12 msgid "DLL Overrides" -msgstr "" +msgstr "דריסת קבצי DLL" #: bottles/frontend/ui/details-preferences.blp:357 #: bottles/frontend/ui/dialog-env-vars.blp:20 msgid "Environment Variables" -msgstr "" +msgstr "משתני הסביבה" #: bottles/frontend/ui/details-preferences.blp:367 msgid "Manage Drives" -msgstr "" +msgstr "ניהול כוננים" #: bottles/frontend/ui/details-preferences.blp:381 msgid "Automatic Snapshots" @@ -888,96 +918,96 @@ msgstr "" msgid "" "Automatically create snapshots before installing software or changing " "settings." -msgstr "" +msgstr "לכידת נתוני מערכת חשובים מיד לפני התקנת תוכנות או עדכון הגדרות" #: bottles/frontend/ui/details-preferences.blp:391 msgid "Compression" -msgstr "" +msgstr "דחיסה" #: bottles/frontend/ui/details-preferences.blp:392 msgid "" "Compress snapshots to reduce space. This will slow down the creation of " "snapshots." -msgstr "" +msgstr "דחיסת נתוני-לכידה כדי להקטין את נפח האחסון. זה ייאט את יצירת הנתונים." #: bottles/frontend/ui/details-preferences.blp:401 msgid "Use Exclusion Patterns" -msgstr "" +msgstr "השתמש בתבניות ויתור" #: bottles/frontend/ui/details-preferences.blp:402 msgid "Exclude paths in snapshots." -msgstr "" +msgstr "וויתור על נתיבי-קבצים בלכידות-נתונים" #: bottles/frontend/ui/details-preferences.blp:405 msgid "Manage Patterns" -msgstr "" +msgstr "ניהול תבניות" #: bottles/frontend/ui/details-taskmanager.blp:17 msgid "Refresh" -msgstr "" +msgstr "רענון" #: bottles/frontend/ui/details-taskmanager.blp:22 msgid "Stop process" -msgstr "" +msgstr "עצירת ההליך" #: bottles/frontend/ui/details-versioning.blp:18 msgid "No Snapshots Found" -msgstr "" +msgstr "לא נמצאו לכידות" #: bottles/frontend/ui/details-versioning.blp:19 msgid "Create your first snapshot to start saving states of your preferences." -msgstr "" +msgstr "צרו את לכידת-הנתונים הראשונה שלכם ושמרו מצבים כפי העדפותיכם" #: bottles/frontend/ui/details-versioning.blp:54 msgid "A short comment" -msgstr "" +msgstr "תגובית קצרה" #: bottles/frontend/ui/details-versioning.blp:58 msgid "Save the bottle state." -msgstr "" +msgstr "שמור את מצב הבקבוק הנוכחי" #: bottles/frontend/ui/details-versioning.blp:78 msgid "Create new Snapshot" -msgstr "" +msgstr "צור לכידת-נתונים חדשה" #: bottles/frontend/ui/details.blp:16 msgid "Details" -msgstr "" +msgstr "פרטים" #: bottles/frontend/ui/details.blp:24 bottles/frontend/ui/details.blp:64 #: bottles/frontend/ui/importer.blp:15 msgid "Go Back" -msgstr "" +msgstr "חזרה" #: bottles/frontend/ui/details.blp:75 msgid "Operations" -msgstr "" +msgstr "פעולות" #: bottles/frontend/ui/dialog-bottle-picker.blp:4 msgid "Select Bottle" -msgstr "" +msgstr "בחירת בקבוק" #: bottles/frontend/ui/dialog-bottle-picker.blp:16 #: bottles/frontend/ui/dialog-proton-alert.blp:16 #: bottles/frontend/ui/dialog-rename.blp:15 #: bottles/frontend/ui/dialog-run-args.blp:20 msgid "Cancel" -msgstr "" +msgstr "ביטול" #: bottles/frontend/ui/dialog-bottle-picker.blp:21 msgid "Select" -msgstr "" +msgstr "בחירה" #: bottles/frontend/ui/dialog-bottle-picker.blp:38 #: bottles/frontend/ui/new.blp:9 bottles/frontend/ui/new.blp:49 #: bottles/frontend/ui/window.blp:25 msgid "Create New Bottle" -msgstr "" +msgstr "יצירת בקבוק חדש" # Translators: Bottles is a proper noun referring to the app #: bottles/frontend/ui/dialog-crash-report.blp:8 msgid "Bottles Crash Report" -msgstr "" +msgstr "דיווח קריסה ל-Bottles" #: bottles/frontend/ui/dialog-crash-report.blp:18 #: bottles/frontend/ui/dialog-duplicate.blp:22 @@ -990,17 +1020,19 @@ msgstr "" #: bottles/frontend/views/bottle_preferences.py:749 #: bottles/frontend/views/preferences.py:201 msgid "_Cancel" -msgstr "" +msgstr "_ביטול" #: bottles/frontend/ui/dialog-crash-report.blp:25 msgid "Send Report" -msgstr "" +msgstr "שליחת דיווח" #: bottles/frontend/ui/dialog-crash-report.blp:44 msgid "" "Bottles crashed last time. Please fill out a report attaching the following " "traceback to help us identify the problem preventing it from happening again." msgstr "" +"אבוי! קרסנו בעת האחרונה. אנא עזרו לנו בניפוי התקלה ומניעתה בעתיד ע\"י מילוי " +"טופס השחזור המצורף." #: bottles/frontend/ui/dialog-crash-report.blp:74 msgid "" @@ -1009,18 +1041,22 @@ msgid "" "new one. Each report requires effort on the part of the developers to " "diagnose, please respect their work and make sure you don't post duplicates." msgstr "" +"תודה על הדיווח המעמיק. לצערינו, מצאנו לפחות דיווח נוסף זהה במאגרים. בדקו " +"בקפדנות שהבעיה הזו טרם דווחה לפני הגשת דיווחים נוספים. הגשת דיווחים כפולים " +"מעמיסה על צוות הפיתוח וגורעת מייעילותם, אנא כבדו את פועלם וודאו שאינכם " +"מגישים דיווחים כפולים או כוזבים." #: bottles/frontend/ui/dialog-crash-report.blp:89 msgid "I still want to report." -msgstr "" +msgstr "ברצוני להמשיך בהליך הדיווח" #: bottles/frontend/ui/dialog-crash-report.blp:95 msgid "Advanced options" -msgstr "" +msgstr "אפשרויות מתקדמות" #: bottles/frontend/ui/dialog-deps-check.blp:13 msgid "Incomplete package" -msgstr "" +msgstr "חבילה לא שלמה" #: bottles/frontend/ui/dialog-deps-check.blp:14 msgid "" @@ -1028,34 +1064,40 @@ msgid "" "dependencies, please contact the package maintainer or use an official " "version." msgstr "" +"מסתמן שגירסה זו איננה מכילה חלק מחבילות-התלות הנחוצות, אנא צרו קשר עם המפיץ " +"למידע נוסף ופתרון התקלה, או שקלו להשתמש בהפצה רשמית של גירסה זו." #: bottles/frontend/ui/dialog-deps-check.blp:18 msgid "Quit" -msgstr "" +msgstr "יציאה" #: bottles/frontend/ui/dialog-dll-overrides.blp:11 msgid "" "Dynamic Link Libraries can be specified to be builtin (provided by Wine) or " "native (provided by the program)." msgstr "" +"ניתן להגדיר ספריות דינמיות מקושרות כך שתהיינה מובנות (ומספוקות ע\"י מיזם " +"WINE) או מקומיות (ומסופקות על-ידינו)." #: bottles/frontend/ui/dialog-dll-overrides.blp:15 msgid "New Override" -msgstr "" +msgstr "דריסה חדשה" #: bottles/frontend/ui/dialog-dll-overrides.blp:21 msgid "Overrides" -msgstr "" +msgstr "דריסות" #: bottles/frontend/ui/dialog-drives.blp:7 msgid "Drives" -msgstr "" +msgstr "כוננים" #: bottles/frontend/ui/dialog-drives.blp:24 msgid "" "These are paths from your host system that are mapped and recognized as " "devices by the runner (e.g. C: D:…)." msgstr "" +"אלה הם נתיבי כוננים וחומרה נוספת שזוהתה ע\"י המערכת שלך. הם נוספו כמיקומים " +"בידי כלי ההרצה" #: bottles/frontend/ui/dialog-drives.blp:27 msgid "Letter" @@ -3039,6 +3081,10 @@ msgstr "" msgid "and many, many, many more!" msgstr "" +#: bottles/frontend/ui/details-preferences.blp:28 +msgid "Improve Direct3D 9/10/11 compatibility by translating it to Vulkan." +msgstr "שיפור תאימות של- Direct3D 9/10/11 ע\"י תרגום ל- Vulkan." + #, fuzzy #~ msgid "Fix installer completion @jntesteves" #~ msgstr "נכשל להתקין תוספים, לאחר 3 נסיונות." diff --git a/po/hu.po b/po/hu.po index bdc37951838..47dde3f8e22 100644 --- a/po/hu.po +++ b/po/hu.po @@ -8,8 +8,8 @@ msgstr "" "Project-Id-Version: bottles\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2023-03-27 13:50+0530\n" -"PO-Revision-Date: 2023-08-05 10:07+0000\n" -"Last-Translator: Ács Zoltán \n" +"PO-Revision-Date: 2025-01-11 23:02+0000\n" +"Last-Translator: Balázs Meskó \n" "Language-Team: Hungarian \n" "Language: hu\n" @@ -17,7 +17,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 5.0-dev\n" +"X-Generator: Weblate 5.10-dev\n" #: bottles/backend/managers/backup.py:48 bottles/backend/managers/backup.py:95 msgid "No path specified" @@ -3063,7 +3063,7 @@ msgstr "" #: data/com.usebottles.bottles.metainfo.xml.in:94 msgid "Fixed \"Add to Steam\" button" -msgstr "\"Hozzáadás Steamhez\" gomb javítva" +msgstr "„Hozzáadás a Steamhez” gomb javítva" #: data/com.usebottles.bottles.metainfo.xml.in:95 msgid "Fixed BottleConfig being not serializable" @@ -3074,9 +3074,8 @@ msgid "Fixed Patool double extraction failing" msgstr "A Patool dupla extrakció hibája javítva" #: data/com.usebottles.bottles.metainfo.xml.in:101 -#, fuzzy msgid "Correct version" -msgstr "Verzió javítása" +msgstr "Helyes verzió" #: data/com.usebottles.bottles.metainfo.xml.in:106 msgid "Fix crash when creating a bottle" @@ -3133,9 +3132,8 @@ msgid "Fix error when downloading if Bottles isn't run from terminal" msgstr "Hiba javítása letöltéskor, ha a Palackok nem terminálból fut" #: data/com.usebottles.bottles.metainfo.xml.in:137 -#, fuzzy msgid "Correct version date" -msgstr "Verzió dátumának javítása" +msgstr "Verzió helyes dátuma" #: data/com.usebottles.bottles.metainfo.xml.in:138 msgid "Hide NVIDIA-related critical errors on non NVIDIA systems" diff --git a/po/id.po b/po/id.po index a42f81f1798..a9be0c91869 100644 --- a/po/id.po +++ b/po/id.po @@ -8,8 +8,8 @@ msgstr "" "Project-Id-Version: bottles\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2023-03-27 13:50+0530\n" -"PO-Revision-Date: 2024-03-29 22:02+0000\n" -"Last-Translator: Reza Almanda \n" +"PO-Revision-Date: 2024-12-16 12:01+0000\n" +"Last-Translator: Arif Budiman \n" "Language-Team: Indonesian \n" "Language: id\n" @@ -17,7 +17,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -"X-Generator: Weblate 5.5-dev\n" +"X-Generator: Weblate 5.9-rc\n" #: bottles/backend/managers/backup.py:48 bottles/backend/managers/backup.py:95 msgid "No path specified" @@ -381,7 +381,7 @@ msgstr "Ubah Pilihan Peluncuran" #: bottles/frontend/ui/details-bottle.blp:135 msgid "Run in Terminal" -msgstr "Jalankan dengan Terminal…" +msgstr "Jalankan dengan Terminal" #: bottles/frontend/ui/details-bottle.blp:148 #, fuzzy @@ -643,7 +643,7 @@ msgstr "Komponen-Komponen" #: bottles/frontend/ui/details-preferences.blp:15 #: bottles/frontend/ui/new.blp:129 msgid "The version of the Wine compatibility layer." -msgstr "" +msgstr "Versi lapisan kompatibilitas Wine." #: bottles/frontend/ui/details-preferences.blp:17 msgid "Updating Runner and components, please wait…" @@ -673,6 +673,7 @@ msgstr "VKD3D" #: bottles/frontend/ui/details-preferences.blp:41 msgid "Improve Direct3D 12 compatibility by translating it to Vulkan." msgstr "" +"Tingkatkan kompatibilitas Direct3D 12 dengan menerjemahkannya ke Vulkan." #: bottles/frontend/ui/details-preferences.blp:43 msgid "Updating VKD3D, please wait…" @@ -712,17 +713,19 @@ msgstr "Pengaturan Layar" #: bottles/frontend/ui/details-preferences.blp:88 msgid "Deep Learning Super Sampling" -msgstr "" +msgstr "Deep Learning Super Sampling" #: bottles/frontend/ui/details-preferences.blp:89 msgid "" "Increase performance at the expense of visuals using DXVK-NVAPI. Only works " "on newer NVIDIA GPUs." msgstr "" +"Meningkatkan performa dengan mengorbankan visual menggunakan DXVK-NVAPI. " +"Hanya berfungsi pada GPU NVIDIA yang lebih baru." #: bottles/frontend/ui/details-preferences.blp:105 msgid "FidelityFX Super Resolution" -msgstr "" +msgstr "FidelityFX Super Resolution" #: bottles/frontend/ui/details-preferences.blp:106 #, fuzzy @@ -731,7 +734,7 @@ msgstr "Meningkatkan performa tetapi juga meningkatkan penggunaan daya." #: bottles/frontend/ui/details-preferences.blp:108 msgid "Manage FidelityFX Super Resolution settings" -msgstr "" +msgstr "Mengelola pengaturan FidelityFX Super Resolution" #: bottles/frontend/ui/details-preferences.blp:125 #, fuzzy @@ -743,15 +746,19 @@ msgid "" "Use the discrete graphics card to increase performance at the expense of " "power consumption." msgstr "" +"Gunakan kartu grafis diskrit untuk meningkatkan performa dengan mengorbankan " +"konsumsi daya." #: bottles/frontend/ui/details-preferences.blp:135 msgid "Post-Processing Effects" -msgstr "" +msgstr "Efek Pasca-Pemrosesan" #: bottles/frontend/ui/details-preferences.blp:136 msgid "" "Add various post-processing effects using vkBasalt. Only works on Vulkan." msgstr "" +"Menambahkan berbagai efek pasca-pemrosesan menggunakan vkBasalt. Hanya " +"berfungsi pada Vulkan." #: bottles/frontend/ui/details-preferences.blp:138 #, fuzzy @@ -761,6 +768,7 @@ msgstr "Kelola pengaturan subsistem wine." #: bottles/frontend/ui/details-preferences.blp:154 msgid "Manage how games should be displayed on the screen using Gamescope." msgstr "" +"Mengelola bagaimana game akan ditampilkan di layar menggunakan Gamescope." #: bottles/frontend/ui/details-preferences.blp:157 msgid "Manage Gamescope settings" @@ -810,6 +818,8 @@ msgid "" "Display monitoring information such as framerate, temperatures, CPU/GPU load " "and more on OpenGL and Vulkan using MangoHud." msgstr "" +"Menampilkan informasi pemantauan seperti framerate, suhu, beban CPU/GPU, dan " +"lainnya di OpenGL dan Vulkan menggunakan MangoHud." #: bottles/frontend/ui/details-preferences.blp:211 #, fuzzy @@ -820,16 +830,20 @@ msgstr "Gunakan GameMode" msgid "" "Apply a set of optimizations to your device. Can improve game performance." msgstr "" +"Menerapkan serangkaian pengoptimalan ke perangkat Anda. Dapat meningkatkan " +"performa game." #: bottles/frontend/ui/details-preferences.blp:221 msgid "Preload Game Files" -msgstr "" +msgstr "Preload File Game" #: bottles/frontend/ui/details-preferences.blp:222 msgid "" "Improve loading time when launching the game multiple times. The game will " "take longer to start for the first time." msgstr "" +"Meningkatkan waktu pemuatan saat meluncurkan game beberapa kali. Game akan " +"membutuhkan waktu lebih lama untuk memulai untuk pertama kalinya." #: bottles/frontend/ui/details-preferences.blp:226 #, fuzzy @@ -848,7 +862,7 @@ msgstr "Beralih tangkap permainan OBS untuk semua peluncuran berikutnya" #: bottles/frontend/ui/details-preferences.blp:251 msgid "Compatibility" -msgstr "" +msgstr "Kompatibilitas" #: bottles/frontend/ui/details-preferences.blp:254 #, fuzzy @@ -861,19 +875,19 @@ msgstr "Memperbarui versi Windows, mohon tunggu…" #: bottles/frontend/ui/details-preferences.blp:266 msgid "Language" -msgstr "" +msgstr "Bahasa" #: bottles/frontend/ui/details-preferences.blp:267 msgid "Choose the language to use with programs." -msgstr "" +msgstr "Pilih bahasa yang akan digunakan dengan program." #: bottles/frontend/ui/details-preferences.blp:275 msgid "Dedicated Sandbox" -msgstr "" +msgstr "Kotak Pasir Khusus" #: bottles/frontend/ui/details-preferences.blp:276 msgid "Use a restricted/managed environment for this bottle." -msgstr "" +msgstr "Gunakan lingkungan terbatas/terkelola untuk botol ini." #: bottles/frontend/ui/details-preferences.blp:279 #, fuzzy @@ -957,6 +971,8 @@ msgid "" "Automatically create snapshots before installing software or changing " "settings." msgstr "" +"Secara otomatis membuat snapshot sebelum menginstal perangkat lunak atau " +"mengubah pengaturan." #: bottles/frontend/ui/details-preferences.blp:391 #, fuzzy @@ -968,14 +984,16 @@ msgid "" "Compress snapshots to reduce space. This will slow down the creation of " "snapshots." msgstr "" +"Kompres snapshot untuk menghemat ruang. Hal ini akan memperlambat pembuatan " +"snapshot." #: bottles/frontend/ui/details-preferences.blp:401 msgid "Use Exclusion Patterns" -msgstr "" +msgstr "Gunakan Pola Pengecualian" #: bottles/frontend/ui/details-preferences.blp:402 msgid "Exclude paths in snapshots." -msgstr "" +msgstr "Kecualikan jalur dalam snapshot." #: bottles/frontend/ui/details-preferences.blp:405 #, fuzzy @@ -1108,7 +1126,7 @@ msgstr "Opsi lanjutan" #: bottles/frontend/ui/dialog-deps-check.blp:13 msgid "Incomplete package" -msgstr "" +msgstr "Paket tidak lengkap" #: bottles/frontend/ui/dialog-deps-check.blp:14 msgid "" @@ -1116,6 +1134,8 @@ msgid "" "dependencies, please contact the package maintainer or use an official " "version." msgstr "" +"Versi Bottles ini tampaknya tidak menyediakan semua ketergantungan inti yang " +"diperlukan, silakan hubungi pengelola paket atau gunakan versi resmi." #: bottles/frontend/ui/dialog-deps-check.blp:18 msgid "Quit" @@ -1185,7 +1205,7 @@ msgstr "Menduplikasi…" #: bottles/frontend/ui/dialog-upgrade-versioning.blp:112 #: bottles/frontend/views/new.py:177 msgid "This could take a while." -msgstr "" +msgstr "Ini bisa memakan waktu beberapa saat." #: bottles/frontend/ui/dialog-duplicate.blp:97 #, fuzzy @@ -1202,7 +1222,7 @@ msgstr "" #: bottles/frontend/ui/dialog-env-vars.blp:31 msgid "Variable Name" -msgstr "" +msgstr "Nama Variabel" #: bottles/frontend/ui/dialog-env-vars.blp:37 #, fuzzy @@ -1211,13 +1231,15 @@ msgstr "Variabel yang sudah ada" #: bottles/frontend/ui/dialog-exclusion-patterns.blp:20 msgid "Exclusion Patterns" -msgstr "" +msgstr "Pola Pengecualian" #: bottles/frontend/ui/dialog-exclusion-patterns.blp:28 msgid "" "Define patterns that will be used to prevent some directories to being " "versioned." msgstr "" +"Tentukan pola yang akan digunakan untuk mencegah beberapa direktori untuk " +"diberi versi." #: bottles/frontend/ui/dialog-exclusion-patterns.blp:31 #, fuzzy @@ -1243,7 +1265,7 @@ msgstr "Simpan" #: bottles/frontend/ui/dialog-gamescope.blp:40 msgid "Manage how games should be displayed." -msgstr "" +msgstr "Mengelola bagaimana game harus ditampilkan." #: bottles/frontend/ui/dialog-gamescope.blp:44 #, fuzzy @@ -1252,7 +1274,7 @@ msgstr "Resolusi permainan" #: bottles/frontend/ui/dialog-gamescope.blp:45 msgid "Uses the resolution of the video game as a reference in pixels." -msgstr "" +msgstr "Menggunakan resolusi video game sebagai referensi dalam piksel." #: bottles/frontend/ui/dialog-gamescope.blp:48 #: bottles/frontend/ui/dialog-gamescope.blp:85 @@ -1274,10 +1296,12 @@ msgid "" "Upscales the resolution when using a resolution higher than the game " "resolution in pixels." msgstr "" +"Meningkatkan resolusi ketika menggunakan resolusi yang lebih tinggi dari " +"resolusi game dalam piksel." #: bottles/frontend/ui/dialog-gamescope.blp:118 msgid "Miscellaneous" -msgstr "" +msgstr "Lain-lain" #: bottles/frontend/ui/dialog-gamescope.blp:121 #, fuzzy @@ -1309,7 +1333,7 @@ msgstr "Layar penuh" #: bottles/frontend/ui/dialog-installer.blp:40 msgid "Do you want to proceed with the installation?" -msgstr "" +msgstr "Apakah Anda ingin melanjutkan penginstalan?" #: bottles/frontend/ui/dialog-installer.blp:45 #, fuzzy @@ -1344,7 +1368,7 @@ msgstr "Pemasangan dependensi gagal." #: bottles/frontend/ui/dialog-installer.blp:149 msgid "Something went wrong." -msgstr "" +msgstr "Ada yang tidak beres." #: bottles/frontend/ui/dialog-journal.blp:9 msgid "All messages" @@ -1376,7 +1400,7 @@ msgstr "Peramban Jurnal" #: bottles/frontend/ui/dialog-journal.blp:53 msgid "Change Logging Level." -msgstr "" +msgstr "Mengubah Tingkat Pencatatan." #: bottles/frontend/ui/dialog-journal.blp:57 msgid "All" @@ -1433,6 +1457,8 @@ msgstr "Pilih direktori" #: bottles/frontend/ui/dialog-launch-options.blp:114 msgid "These settings will override the default settings for this executable." msgstr "" +"Pengaturan ini akan menggantikan pengaturan default untuk file yang dapat " +"dieksekusi ini." #: bottles/frontend/ui/dialog-launch-options.blp:115 #, fuzzy @@ -1450,7 +1476,7 @@ msgstr "Desktop Virtual" #: bottles/frontend/ui/dialog-proton-alert.blp:4 msgid "Proton Disclaimer" -msgstr "" +msgstr "Penyangkalan Proton" #: bottles/frontend/ui/dialog-proton-alert.blp:21 #, fuzzy @@ -1471,10 +1497,21 @@ msgid "" "the runner's provider, is not responsible for any problems and we ask that " "you do not report to them." msgstr "" +"Waspadalah, menggunakan runner berbasis Proton dalam bottle non-Steam dapat " +"menyebabkan masalah dan membuatnya tidak berfungsi dengan baik.\n" +"\n" +"Kami lebih menyarankan untuk menggunakan Wine-GE, versi Proton yang " +"dimaksudkan untuk berjalan di luar Steam.\n" +"\n" +"Proses akan secara otomatis mengaktifkan runtime Steam (jika ada dalam " +"sistem dan terdeteksi oleh Bottles) untuk memungkinkannya mengakses pustaka " +"yang diperlukan dan membatasi masalah kompatibilitas. Perlu diketahui bahwa " +"GloriousEggroll, penyedia runner, tidak bertanggung jawab atas masalah apa " +"pun dan kami meminta Anda untuk tidak melapor kepada mereka." #: bottles/frontend/ui/dialog-proton-alert.blp:43 msgid "I got it." -msgstr "" +msgstr "Aku mengerti." #: bottles/frontend/ui/dialog-rename.blp:7 msgid "Rename" @@ -1516,7 +1553,7 @@ msgstr "Pengaturan Gamescope" #: bottles/frontend/ui/dialog-sandbox.blp:25 msgid "Share Network" -msgstr "" +msgstr "Berbagi Jaringan" #: bottles/frontend/ui/dialog-sandbox.blp:34 #, fuzzy @@ -1545,7 +1582,7 @@ msgstr "Pembuatan versi" #: bottles/frontend/ui/dialog-upgrade-versioning.blp:69 msgid "The new bottle versioning system has landed." -msgstr "" +msgstr "Sistem versi botol yang baru telah diluncurkan." #: bottles/frontend/ui/dialog-upgrade-versioning.blp:83 msgid "" diff --git a/po/it.po b/po/it.po index b5a9190eab7..5394749a787 100644 --- a/po/it.po +++ b/po/it.po @@ -8,8 +8,8 @@ msgstr "" "Project-Id-Version: bottles\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2023-03-27 13:50+0530\n" -"PO-Revision-Date: 2024-07-28 21:09+0000\n" -"Last-Translator: Mqrco0 \n" +"PO-Revision-Date: 2024-12-14 15:37+0000\n" +"Last-Translator: albanobattistella \n" "Language-Team: Italian \n" "Language: it\n" @@ -17,7 +17,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 5.7-dev\n" +"X-Generator: Weblate 5.9-rc\n" #: bottles/backend/managers/backup.py:48 bottles/backend/managers/backup.py:95 msgid "No path specified" @@ -1931,9 +1931,8 @@ msgid "C_reate" msgstr "C_rea" #: bottles/frontend/ui/new.blp:53 -#, fuzzy msgid "Bottle Name" -msgstr "Nome bottiglia" +msgstr "Nome della bottiglia" #: bottles/frontend/ui/new.blp:75 msgid "_Application" @@ -2600,6 +2599,8 @@ msgid "" "Based on Valve's Wine, includes staging, Proton and Steam-specific patches. " "Requires the Steam Runtime turned on." msgstr "" +"Basato su Wine di Valve, include staging, Proton e patch specifiche di " +"Steam. Richiede Steam Runtime attivato." #: bottles/frontend/views/preferences.py:250 msgid "Other" @@ -3125,6 +3126,7 @@ msgstr "Miglioramenti della qualità di vita:" #: data/com.usebottles.bottles.metainfo.xml.in:114 msgid "Replace emote-love icon with library in library page" msgstr "" +"Sostituisci l'icona emote-love con la libreria nella pagina della libreria" #: data/com.usebottles.bottles.metainfo.xml.in:115 msgid "Add toast for \"Run Executable\"" @@ -3136,7 +3138,7 @@ msgstr "Correzioni di bug:" #: data/com.usebottles.bottles.metainfo.xml.in:119 msgid "Adding shortcut to Steam resulted an error" -msgstr "" +msgstr "L'aggiunta di un collegamento a Steam ha generato un errore" #: data/com.usebottles.bottles.metainfo.xml.in:120 msgid "Importing backups resulted an error" @@ -3152,6 +3154,8 @@ msgid "" "Various library related fixes, like empty covers, and crashes related to " "missing entries" msgstr "" +"Varie correzioni relative alla libreria, come copertine vuote e arresti " +"anomali correlati a voci mancanti" #: data/com.usebottles.bottles.metainfo.xml.in:123 msgid "Fix various issues related to text encoding" @@ -3169,7 +3173,7 @@ msgstr "Data della versione corretta" #: data/com.usebottles.bottles.metainfo.xml.in:138 msgid "Hide NVIDIA-related critical errors on non NVIDIA systems" -msgstr "" +msgstr "Nascondi gli errori critici correlati a NVIDIA sui sistemi non NVIDIA" #: data/com.usebottles.bottles.metainfo.xml.in:145 msgid "Gamescope improvements and fixes" @@ -3205,6 +3209,8 @@ msgstr "Più variabili per lo scripting del programma di installazione" #: data/com.usebottles.bottles.metainfo.xml.in:152 msgid "Fix onboard dialog showing \"All ready\" while it was in fact not ready" msgstr "" +"Corretto la finestra di dialogo di bordo che mostrava \"Tutto pronto\" " +"quando in realtà non era pronto" #: data/com.usebottles.bottles.metainfo.xml.in:153 msgid "Improvement to build system" diff --git a/po/ka.po b/po/ka.po new file mode 100644 index 00000000000..8016784e432 --- /dev/null +++ b/po/ka.po @@ -0,0 +1,3053 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the bottles package. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: bottles\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2023-09-27 10:57+0530\n" +"PO-Revision-Date: 2024-12-28 04:32+0000\n" +"Last-Translator: Temuri Doghonadze \n" +"Language-Team: Georgian \n" +"Language: ka\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 5.10-dev\n" + +#: bottles/backend/managers/backup.py:48 bottles/backend/managers/backup.py:95 +msgid "No path specified" +msgstr "ბილიკი მითითებული არაა" + +#: bottles/backend/managers/backup.py:56 +#, python-brace-format +msgid "Backup {0}" +msgstr "{0}-ის მარქაფი" + +#: bottles/backend/managers/backup.py:103 +#, python-brace-format +msgid "Importing backup: {0}" +msgstr "" + +#: bottles/backend/managers/manager.py:1076 +#: bottles/backend/managers/manager.py:1396 +#: bottles/backend/managers/manager.py:1397 +#, python-format +msgid "Failed to install dependency: %s" +msgstr "" + +#: bottles/backend/managers/manager.py:1115 +msgid "Fail to install components, tried 3 times." +msgstr "" + +#: bottles/backend/managers/manager.py:1126 +msgid "Missing essential components. Installing…" +msgstr "" + +#: bottles/backend/managers/manager.py:1203 +msgid "Failed to create bottle directory." +msgstr "" + +#: bottles/backend/managers/manager.py:1215 +msgid "Failed to create placeholder directory/file." +msgstr "" + +#: bottles/backend/managers/manager.py:1220 +msgid "Generating bottle configuration…" +msgstr "" + +#: bottles/backend/managers/manager.py:1243 +msgid "Template found, applying…" +msgstr "" + +#. execute wineboot on the bottle path +#: bottles/backend/managers/manager.py:1255 +msgid "The Wine config is being updated…" +msgstr "" + +#: bottles/backend/managers/manager.py:1257 +msgid "Wine config updated!" +msgstr "" + +#: bottles/backend/managers/manager.py:1265 +msgid "Running as Flatpak, sandboxing userdir…" +msgstr "" + +#: bottles/backend/managers/manager.py:1267 +msgid "Sandboxing userdir…" +msgstr "მომხმარებლის საქაღალდის სენდბოქსი…" + +#: bottles/backend/managers/manager.py:1308 +msgid "Setting Windows version…" +msgstr "" + +#: bottles/backend/managers/manager.py:1318 +msgid "Apply CMD default settings…" +msgstr "" + +#: bottles/backend/managers/manager.py:1326 +msgid "Optimizing environment…" +msgstr "გარემოს ოპტიმიზაცია…" + +#: bottles/backend/managers/manager.py:1337 +#, python-brace-format +msgid "Applying environment: {0}…" +msgstr "" + +#: bottles/backend/managers/manager.py:1347 +msgid "(!) Using a custom environment recipe…" +msgstr "" + +#: bottles/backend/managers/manager.py:1350 +msgid "(!) Recipe not not found or not valid…" +msgstr "" + +#: bottles/backend/managers/manager.py:1367 +msgid "Installing DXVK…" +msgstr "მიმდინარეობს DXVK-ის დაყენება…" + +#: bottles/backend/managers/manager.py:1375 +msgid "Installing VKD3D…" +msgstr "მიმდინარეობს VKD3D-ის დაყენება…" + +#: bottles/backend/managers/manager.py:1384 +msgid "Installing DXVK-NVAPI…" +msgstr "მიმდინარეობს DXVK-NVAPI-ის დაყენება…" + +#: bottles/backend/managers/manager.py:1393 +#, python-format +msgid "Installing dependency: %s …" +msgstr "" + +#: bottles/backend/managers/manager.py:1407 +msgid "Creating versioning state 0…" +msgstr "" + +#: bottles/backend/managers/manager.py:1415 +msgid "Finalizing…" +msgstr "დასრულება…" + +#: bottles/backend/managers/manager.py:1426 +msgid "Caching template…" +msgstr "მიმდინარეობს ნიმუშის დაკეშვა…" + +#: bottles/backend/managers/versioning.py:83 +msgid "Committing state …" +msgstr "" + +#: bottles/backend/managers/versioning.py:90 +msgid "Nothing to commit" +msgstr "" + +#: bottles/backend/managers/versioning.py:96 +#, python-brace-format +msgid "New state [{0}] created successfully!" +msgstr "" + +#: bottles/backend/managers/versioning.py:123 +msgid "States list retrieved successfully!" +msgstr "" + +#: bottles/backend/managers/versioning.py:153 +#, python-brace-format +msgid "State {0} restored successfully!" +msgstr "" + +#: bottles/backend/managers/versioning.py:155 +msgid "Restoring state {} …" +msgstr "" + +#: bottles/backend/managers/versioning.py:162 +msgid "State not found" +msgstr "" + +#: bottles/backend/managers/versioning.py:168 +msgid "State {} is already the active state" +msgstr "" + +#: bottles/frontend/main.py:111 +msgid "Show version" +msgstr "ვერსიის ჩვენება" + +#: bottles/frontend/main.py:119 +msgid "Executable path" +msgstr "გამშვები ფაილის ბილიკი" + +#: bottles/frontend/main.py:127 +msgid "lnk path" +msgstr "ბმულის ბილიკი" + +#: bottles/frontend/main.py:135 bottles/frontend/ui/library-entry.blp:118 +#: bottles/frontend/ui/list-entry.blp:5 +msgid "Bottle name" +msgstr "ბოთლის სახელი" + +#: bottles/frontend/main.py:143 +msgid "Pass arguments" +msgstr "არგუმენტების გადაცემა" + +#: bottles/frontend/main.py:202 +msgid "Invalid URI (syntax: bottles:run//)" +msgstr "" + +#: bottles/frontend/main.py:242 +msgid "[Quit] request received." +msgstr "" + +#: bottles/frontend/main.py:252 +msgid "[Help] request received." +msgstr "" + +#: bottles/frontend/main.py:260 +msgid "[Refresh] request received." +msgstr "" + +#: bottles/frontend/main.py:293 +msgid "Donate" +msgstr "შემოწირულობა" + +#: bottles/frontend/main.py:298 +msgid "Third-Party Libraries and Special Thanks" +msgstr "" + +#: bottles/frontend/main.py:324 +msgid "Sponsored and Funded by" +msgstr "" + +#: bottles/frontend/ui/about.blp:5 +msgid "Copyright © 2017 Bottles Developers" +msgstr "" + +#: bottles/frontend/ui/about.blp:10 +msgid "Bottles Developers" +msgstr "ბოთლის სასტავი" + +#: bottles/frontend/ui/about.blp:12 +msgid "translator_credits" +msgstr "მთარგმნელის_შესახებ" + +#: bottles/frontend/ui/component-entry.blp:4 +msgid "Component version" +msgstr "კომპონენტის ვერსია" + +#: bottles/frontend/ui/component-entry.blp:12 +#: bottles/frontend/ui/dependency-entry.blp:29 +#: bottles/frontend/ui/program-entry.blp:77 +msgid "Uninstall" +msgstr "წაშლა" + +#: bottles/frontend/ui/component-entry.blp:23 +#: bottles/frontend/ui/importer-entry.blp:13 +msgid "Browse Files" +msgstr "ფაილის არჩევა" + +#: bottles/frontend/ui/component-entry.blp:34 +msgid "" +"The installation failed. This may be due to a repository error, partial " +"download or checksum mismatch. Press to try again." +msgstr "" + +#: bottles/frontend/ui/component-entry.blp:45 +msgid "Download & Install" +msgstr "" + +#: bottles/frontend/ui/component-entry.blp:58 +msgid "0%" +msgstr "0%" + +#: bottles/frontend/ui/dependency-entry.blp:16 +msgid "Show Manifest" +msgstr "მანიფესტის ჩვენება" + +#: bottles/frontend/ui/dependency-entry.blp:20 +msgid "License" +msgstr "ლიცენზია" + +#: bottles/frontend/ui/dependency-entry.blp:24 +msgid "Reinstall" +msgstr "გადაყენება" + +#: bottles/frontend/ui/dependency-entry.blp:36 +#: bottles/frontend/ui/installer-entry.blp:27 +msgid "Report a Bug…" +msgstr "შეცდომის პატაკი…" + +#: bottles/frontend/ui/dependency-entry.blp:42 +msgid "Dependency name" +msgstr "დამოკიდებულების სახელი" + +#: bottles/frontend/ui/dependency-entry.blp:44 +msgid "Dependency description" +msgstr "დამოკიდებულების აღწერა" + +#: bottles/frontend/ui/dependency-entry.blp:51 +msgid "Category" +msgstr "კატეგორია" + +#: bottles/frontend/ui/dependency-entry.blp:64 +msgid "Download & Install this Dependency" +msgstr "" + +#: bottles/frontend/ui/dependency-entry.blp:79 +msgid "" +"An installation error occurred. Restart Bottles to read the Crash Report or " +"run it via terminal to read the output." +msgstr "" + +#: bottles/frontend/ui/dependency-entry.blp:93 +msgid "Dependency Menu" +msgstr "დამოკიდებულების მენიუ" + +#: bottles/frontend/ui/details-bottle.blp:16 +msgid "Troubleshooting" +msgstr "პრობლემების გადაჭრა" + +#: bottles/frontend/ui/details-bottle.blp:24 +msgid "Browse Files…" +msgstr "ფაილების დათვალიერება…" + +#: bottles/frontend/ui/details-bottle.blp:28 +msgid "Duplicate Bottle…" +msgstr "ბოთლის დუბლირება…" + +#: bottles/frontend/ui/details-bottle.blp:32 +#: bottles/frontend/ui/importer.blp:73 +msgid "This is the complete archive of your bottle, including personal files." +msgstr "" + +#: bottles/frontend/ui/details-bottle.blp:33 +msgid "Full Backup…" +msgstr "სრული მარქაფი…" + +#: bottles/frontend/ui/details-bottle.blp:37 +#: bottles/frontend/ui/importer.blp:68 +msgid "" +"This is just the bottle configuration, it's perfect if you want to create a " +"new one but without personal files." +msgstr "" + +#: bottles/frontend/ui/details-bottle.blp:38 +msgid "Export Configuration…" +msgstr "კონფიგურაციის გატანა…" + +#: bottles/frontend/ui/details-bottle.blp:45 +#: bottles/frontend/views/bottle_details.py:347 +msgid "Show Hidden Programs" +msgstr "" + +#: bottles/frontend/ui/details-bottle.blp:49 +msgid "Search for new programs" +msgstr "" + +#: bottles/frontend/ui/details-bottle.blp:56 +msgid "Delete Bottle…" +msgstr "ბოთლის წაშლა…" + +#: bottles/frontend/ui/details-bottle.blp:73 +#: bottles/frontend/ui/details-dependencies.blp:99 +#: bottles/frontend/ui/details-installers.blp:68 +msgid "Secondary Menu" +msgstr "მეორადი მენიუ" + +#: bottles/frontend/ui/details-bottle.blp:90 +msgid "Force Stop all Processes" +msgstr "" + +#: bottles/frontend/ui/details-bottle.blp:94 +msgid "Simulate a Windows system shutdown." +msgstr "" + +#: bottles/frontend/ui/details-bottle.blp:95 +msgid "Shutdown" +msgstr "გამორთვა" + +#: bottles/frontend/ui/details-bottle.blp:99 +msgid "Simulate a Windows system reboot." +msgstr "" + +#: bottles/frontend/ui/details-bottle.blp:100 +msgid "Reboot" +msgstr "გადატვირთვა" + +#: bottles/frontend/ui/details-bottle.blp:118 +#: bottles/frontend/ui/dialog-launch-options.blp:6 +msgid "Launch Options" +msgstr "გაშვების პარამეტრები" + +#: bottles/frontend/ui/details-bottle.blp:135 +msgid "Run in Terminal" +msgstr "ტერმინალში გაშვება" + +#: bottles/frontend/ui/details-bottle.blp:148 +msgid "Drop files to execute them" +msgstr "" + +#: bottles/frontend/ui/details-bottle.blp:164 +msgid "My bottle" +msgstr "" + +#: bottles/frontend/ui/details-bottle.blp:177 +msgid "Win64" +msgstr "Win64" + +#: bottles/frontend/ui/details-bottle.blp:189 +#: bottles/frontend/ui/list-entry.blp:12 bottles/frontend/ui/new.blp:71 +msgid "Environment" +msgstr "გარემო" + +#: bottles/frontend/ui/details-bottle.blp:201 +#: bottles/frontend/ui/details-preferences.blp:14 +#: bottles/frontend/ui/new.blp:128 +msgid "Runner" +msgstr "გამშვები" + +#: bottles/frontend/ui/details-bottle.blp:213 +#: bottles/frontend/ui/list-entry.blp:21 +msgid "Versioning enabled for this bottle" +msgstr "" + +#: bottles/frontend/ui/details-bottle.blp:218 +msgid "Versioning is active for this bottle." +msgstr "" + +#: bottles/frontend/ui/details-bottle.blp:227 +#: bottles/frontend/ui/list-entry.blp:31 +msgid "0" +msgstr "0" + +#: bottles/frontend/ui/details-bottle.blp:247 +msgid "Run Executable…" +msgstr "" + +#: bottles/frontend/ui/details-bottle.blp:272 +msgid "Programs" +msgstr "პროგრამები" + +#: bottles/frontend/ui/details-bottle.blp:275 +msgid "" +"Click \"Run Executable…\" to run an executable, \"Add Shortcuts…\" to add an " +"executable to the Programs list, or \"Install Programs…\" to install " +"programs curated by the community." +msgstr "" + +#: bottles/frontend/ui/details-bottle.blp:298 +msgid "Add Shortcuts…" +msgstr "" + +#: bottles/frontend/ui/details-bottle.blp:325 +msgid "Install Programs…" +msgstr "" + +#: bottles/frontend/ui/details-bottle.blp:346 +msgid "Options" +msgstr "მორგება" + +#: bottles/frontend/ui/details-bottle.blp:350 +#: bottles/frontend/views/details.py:141 +msgid "Settings" +msgstr "მორგება" + +#: bottles/frontend/ui/details-bottle.blp:351 +msgid "Configure bottle settings." +msgstr "" + +#: bottles/frontend/ui/details-bottle.blp:360 +#: bottles/frontend/views/details.py:145 +msgid "Dependencies" +msgstr "დამოკიდებულებები" + +#: bottles/frontend/ui/details-bottle.blp:361 +msgid "Install dependencies for programs." +msgstr "" + +#: bottles/frontend/ui/details-bottle.blp:370 +#: bottles/frontend/ui/details-preferences.blp:376 +#: bottles/frontend/views/details.py:149 +msgid "Snapshots" +msgstr "სწრაფი ასლები" + +#: bottles/frontend/ui/details-bottle.blp:371 +msgid "Create and manage bottle states." +msgstr "" + +#: bottles/frontend/ui/details-bottle.blp:380 +#: bottles/frontend/ui/details-bottle.blp:426 +#: bottles/frontend/views/details.py:157 +msgid "Task Manager" +msgstr "ამოცანების მმართველი" + +#: bottles/frontend/ui/details-bottle.blp:381 +msgid "Manage running programs." +msgstr "" + +#: bottles/frontend/ui/details-bottle.blp:390 +msgid "Tools" +msgstr "ხელსაწყოები" + +#: bottles/frontend/ui/details-bottle.blp:394 +msgid "Command Line" +msgstr "ბრძანების ველი" + +#: bottles/frontend/ui/details-bottle.blp:395 +msgid "Run commands inside the Bottle." +msgstr "" + +#: bottles/frontend/ui/details-bottle.blp:404 +msgid "Registry Editor" +msgstr "რეესტრის რედაქტორი" + +#: bottles/frontend/ui/details-bottle.blp:405 +msgid "Edit the internal registry." +msgstr "" + +#: bottles/frontend/ui/details-bottle.blp:413 +msgid "Legacy Wine Tools" +msgstr "" + +#: bottles/frontend/ui/details-bottle.blp:417 +msgid "Explorer" +msgstr "გამცილებელი" + +#: bottles/frontend/ui/details-bottle.blp:435 +msgid "Debugger" +msgstr "გამმართველი" + +#: bottles/frontend/ui/details-bottle.blp:444 +#: bottles/frontend/ui/importer.blp:69 bottles/frontend/ui/new.blp:145 +msgid "Configuration" +msgstr "კონფიგურაცია" + +#: bottles/frontend/ui/details-bottle.blp:453 +msgid "Uninstaller" +msgstr "წაშლის პროგრამა" + +#: bottles/frontend/ui/details-bottle.blp:462 +msgid "Control Panel" +msgstr "მართვის პანელი" + +#: bottles/frontend/ui/details-dependencies.blp:9 +msgid "Search for dependencies…" +msgstr "" + +#: bottles/frontend/ui/details-dependencies.blp:22 +#: bottles/frontend/ui/preferences.blp:199 +#: bottles/frontend/ui/preferences.blp:247 +msgid "You're offline :(" +msgstr "" + +#: bottles/frontend/ui/details-dependencies.blp:25 +msgid "Bottles is running in offline mode, so dependencies are not available." +msgstr "" + +#: bottles/frontend/ui/details-dependencies.blp:47 +msgid "" +"Dependencies are resources that improve compatibility of Windows software.\n" +"\n" +"Files on this page are provided by third parties under a proprietary " +"license. By installing them, you agree with their respective licensing terms." +msgstr "" + +#: bottles/frontend/ui/details-dependencies.blp:76 +msgid "Report a problem or a missing dependency." +msgstr "" + +#: bottles/frontend/ui/details-dependencies.blp:77 +msgid "Report Missing Dependency" +msgstr "" + +#: bottles/frontend/ui/details-dependencies.blp:81 +msgid "Read Documentation." +msgstr "" + +#: bottles/frontend/ui/details-dependencies.blp:82 +#: bottles/frontend/ui/details-installers.blp:51 +#: bottles/frontend/ui/details-versioning.blp:37 +msgid "Documentation" +msgstr "დოკუმენტაცია" + +#: bottles/frontend/ui/details-dependencies.blp:92 +#: bottles/frontend/ui/details-installers.blp:61 +#: bottles/frontend/ui/window.blp:46 +msgid "Search" +msgstr "ძებნა" + +#: bottles/frontend/ui/details-installers.blp:9 +msgid "Search for Programs…" +msgstr "" + +#: bottles/frontend/ui/details-installers.blp:15 +msgid "" +"Install programs curated by our community.\n" +"\n" +"Files on this page are provided by third parties under a proprietary " +"license. By installing them, you agree with their respective licensing terms." +msgstr "" + +#: bottles/frontend/ui/details-installers.blp:29 +msgid "No Installers Found" +msgstr "" + +#: bottles/frontend/ui/details-installers.blp:32 +msgid "" +"The repository is unreachable or no installer is compatible with this bottle." +msgstr "" + +#: bottles/frontend/ui/details-installers.blp:50 +#: bottles/frontend/ui/details-versioning.blp:36 +#: bottles/frontend/ui/preferences.blp:82 +msgid "Read Documentation" +msgstr "" + +#: bottles/frontend/ui/details-preferences.blp:6 +#: bottles/frontend/ui/dialog-duplicate.blp:52 bottles/frontend/ui/new.blp:53 +msgid "Name" +msgstr "სახელი" + +#: bottles/frontend/ui/details-preferences.blp:11 +msgid "Components" +msgstr "კომპონენტები" + +#: bottles/frontend/ui/details-preferences.blp:15 +#: bottles/frontend/ui/new.blp:129 +msgid "The version of the Wine compatibility layer." +msgstr "" + +#: bottles/frontend/ui/details-preferences.blp:17 +msgid "Updating Runner and components, please wait…" +msgstr "" + +#: bottles/frontend/ui/details-preferences.blp:27 +#: bottles/frontend/ui/preferences.blp:274 +msgid "DXVK" +msgstr "DXVK" + +#: bottles/frontend/ui/details-preferences.blp:28 +msgid "Improve Direct3D 8/9/10/11 compatibility by translating it to Vulkan." +msgstr "" + +#: bottles/frontend/ui/details-preferences.blp:30 +msgid "Updating DXVK, please wait…" +msgstr "" + +#: bottles/frontend/ui/details-preferences.blp:40 +#: bottles/frontend/ui/preferences.blp:278 +msgid "VKD3D" +msgstr "VKD3D" + +#: bottles/frontend/ui/details-preferences.blp:41 +msgid "Improve Direct3D 12 compatibility by translating it to Vulkan." +msgstr "" + +#: bottles/frontend/ui/details-preferences.blp:43 +msgid "Updating VKD3D, please wait…" +msgstr "" + +#: bottles/frontend/ui/details-preferences.blp:54 +msgid "DXVK NVAPI" +msgstr "" + +#: bottles/frontend/ui/details-preferences.blp:58 +#: bottles/frontend/ui/details-preferences.blp:93 +msgid "Updating DXVK-NVAPI, please wait…" +msgstr "" + +#: bottles/frontend/ui/details-preferences.blp:68 +#: bottles/frontend/ui/preferences.blp:286 +msgid "LatencyFleX" +msgstr "LatencyFleX" + +#: bottles/frontend/ui/details-preferences.blp:69 +msgid "Increase responsiveness. Can be detected by some anti-cheat software." +msgstr "" + +#: bottles/frontend/ui/details-preferences.blp:71 +msgid "Updating LatencyFleX, please wait…" +msgstr "" + +#: bottles/frontend/ui/details-preferences.blp:84 +msgid "Display" +msgstr "ჩვენება" + +#: bottles/frontend/ui/details-preferences.blp:88 +msgid "Deep Learning Super Sampling" +msgstr "" + +#: bottles/frontend/ui/details-preferences.blp:89 +msgid "" +"Increase performance at the expense of visuals using DXVK-NVAPI. Only works " +"on newer NVIDIA GPUs." +msgstr "" + +#: bottles/frontend/ui/details-preferences.blp:105 +msgid "FidelityFX Super Resolution" +msgstr "" + +#: bottles/frontend/ui/details-preferences.blp:106 +msgid "Increase performance at the expense of visuals. Only works on Vulkan." +msgstr "" + +#: bottles/frontend/ui/details-preferences.blp:108 +msgid "Manage FidelityFX Super Resolution settings" +msgstr "" + +#: bottles/frontend/ui/details-preferences.blp:125 +msgid "Discrete Graphics" +msgstr "" + +#: bottles/frontend/ui/details-preferences.blp:126 +msgid "" +"Use the discrete graphics card to increase performance at the expense of " +"power consumption." +msgstr "" + +#: bottles/frontend/ui/details-preferences.blp:135 +msgid "Post-Processing Effects" +msgstr "" + +#: bottles/frontend/ui/details-preferences.blp:136 +msgid "" +"Add various post-processing effects using vkBasalt. Only works on Vulkan." +msgstr "" + +#: bottles/frontend/ui/details-preferences.blp:138 +msgid "Manage Post-Processing Layer settings" +msgstr "" + +#: bottles/frontend/ui/details-preferences.blp:154 +msgid "Manage how games should be displayed on the screen using Gamescope." +msgstr "" + +#: bottles/frontend/ui/details-preferences.blp:157 +msgid "Manage Gamescope settings" +msgstr "" + +#: bottles/frontend/ui/details-preferences.blp:171 +msgid "Advanced Display Settings" +msgstr "" + +#: bottles/frontend/ui/details-preferences.blp:184 +msgid "Performance" +msgstr "წარმადობა" + +#: bottles/frontend/ui/details-preferences.blp:188 +msgid "Enable synchronization to increase performance of multicore processors." +msgstr "" + +#: bottles/frontend/ui/details-preferences.blp:189 +msgid "Synchronization" +msgstr "სინქრონიზაცია" + +#: bottles/frontend/ui/details-preferences.blp:193 +msgid "System" +msgstr "სისტემა" + +#: bottles/frontend/ui/details-preferences.blp:194 +msgid "Esync" +msgstr "Esync" + +#: bottles/frontend/ui/details-preferences.blp:195 +msgid "Fsync" +msgstr "Fsync" + +#: bottles/frontend/ui/details-preferences.blp:201 +msgid "Monitor Performance" +msgstr "" + +#: bottles/frontend/ui/details-preferences.blp:202 +msgid "" +"Display monitoring information such as framerate, temperatures, CPU/GPU load " +"and more on OpenGL and Vulkan using MangoHud." +msgstr "" + +#: bottles/frontend/ui/details-preferences.blp:205 +msgid "Manage MangoHud settings" +msgstr "" + +#: bottles/frontend/ui/details-preferences.blp:210 +msgid "Feral GameMode" +msgstr "" + +#: bottles/frontend/ui/details-preferences.blp:211 +msgid "" +"Apply a set of optimizations to your device. Can improve game performance." +msgstr "" + +#: bottles/frontend/ui/details-preferences.blp:220 +msgid "Preload Game Files" +msgstr "" + +#: bottles/frontend/ui/details-preferences.blp:221 +msgid "" +"Improve loading time when launching the game multiple times. The game will " +"take longer to start for the first time." +msgstr "" + +#: bottles/frontend/ui/details-preferences.blp:225 +msgid "Manage vmtouch settings" +msgstr "" + +#: bottles/frontend/ui/details-preferences.blp:240 +msgid "OBS Game Capture" +msgstr "" + +#: bottles/frontend/ui/details-preferences.blp:241 +msgid "Toggle OBS Game Capture for all Vulkan and OpenGL programs." +msgstr "" + +#: bottles/frontend/ui/details-preferences.blp:250 +msgid "Compatibility" +msgstr "თავსებადობა" + +#: bottles/frontend/ui/details-preferences.blp:253 +msgid "Windows Version" +msgstr "" + +#: bottles/frontend/ui/details-preferences.blp:256 +msgid "Updating Windows version, please wait…" +msgstr "" + +#: bottles/frontend/ui/details-preferences.blp:265 +msgid "Language" +msgstr "ენა" + +#: bottles/frontend/ui/details-preferences.blp:266 +msgid "Choose the language to use with programs." +msgstr "" + +#: bottles/frontend/ui/details-preferences.blp:274 +msgid "Dedicated Sandbox" +msgstr "" + +#: bottles/frontend/ui/details-preferences.blp:275 +msgid "Use a restricted/managed environment for this bottle." +msgstr "" + +#: bottles/frontend/ui/details-preferences.blp:278 +msgid "Manage the Sandbox Permissions" +msgstr "" + +#: bottles/frontend/ui/details-preferences.blp:294 +msgid "Bottles Runtime" +msgstr "" + +#: bottles/frontend/ui/details-preferences.blp:295 +msgid "" +"Provide a bundle of extra libraries for more compatibility. Disable it if " +"you run into issues." +msgstr "" + +#: bottles/frontend/ui/details-preferences.blp:305 +msgid "Steam Runtime" +msgstr "" + +#: bottles/frontend/ui/details-preferences.blp:306 +msgid "" +"Provide a bundle of extra libraries for more compatibility with Steam games. " +"Disable it if you run into issues." +msgstr "" + +#: bottles/frontend/ui/details-preferences.blp:314 +#: bottles/frontend/ui/dialog-launch-options.blp:83 +msgid "Working Directory" +msgstr "სამუშაო საქაღალდე" + +#: bottles/frontend/ui/details-preferences.blp:317 +#: bottles/frontend/ui/dialog-launch-options.blp:59 +#: bottles/frontend/ui/dialog-launch-options.blp:90 +#: bottles/frontend/ui/new.blp:150 bottles/frontend/ui/new.blp:181 +#: bottles/frontend/ui/preferences.blp:157 +msgid "Reset to Default" +msgstr "ნაგულისხმებ მნიშვნელობაზე დაბრუნება" + +#: bottles/frontend/ui/details-preferences.blp:338 +#: bottles/frontend/ui/preferences.blp:178 bottles/frontend/views/new.py:78 +#: bottles/frontend/views/preferences.py:221 +msgid "(Default)" +msgstr "(ნაგულისხმევი)" + +#: bottles/frontend/ui/details-preferences.blp:346 +#: bottles/frontend/ui/dialog-dll-overrides.blp:7 +#: bottles/frontend/ui/dialog-dll-overrides.blp:12 +msgid "DLL Overrides" +msgstr "" + +#: bottles/frontend/ui/details-preferences.blp:356 +#: bottles/frontend/ui/dialog-env-vars.blp:20 +msgid "Environment Variables" +msgstr "გარემოს ცვლადები" + +#: bottles/frontend/ui/details-preferences.blp:366 +msgid "Manage Drives" +msgstr "" + +#: bottles/frontend/ui/details-preferences.blp:380 +msgid "Automatic Snapshots" +msgstr "" + +#: bottles/frontend/ui/details-preferences.blp:381 +msgid "" +"Automatically create snapshots before installing software or changing " +"settings." +msgstr "" + +#: bottles/frontend/ui/details-preferences.blp:390 +msgid "Compression" +msgstr "შეკუმშვა" + +#: bottles/frontend/ui/details-preferences.blp:391 +msgid "" +"Compress snapshots to reduce space. This will slow down the creation of " +"snapshots." +msgstr "" + +#: bottles/frontend/ui/details-preferences.blp:400 +msgid "Use Exclusion Patterns" +msgstr "" + +#: bottles/frontend/ui/details-preferences.blp:401 +msgid "Exclude paths in snapshots." +msgstr "" + +#: bottles/frontend/ui/details-preferences.blp:404 +msgid "Manage Patterns" +msgstr "" + +#: bottles/frontend/ui/details-taskmanager.blp:17 +msgid "Refresh" +msgstr "განახლება" + +#: bottles/frontend/ui/details-taskmanager.blp:22 +msgid "Stop process" +msgstr "" + +#: bottles/frontend/ui/details-versioning.blp:18 +msgid "No Snapshots Found" +msgstr "" + +#: bottles/frontend/ui/details-versioning.blp:19 +msgid "Create your first snapshot to start saving states of your preferences." +msgstr "" + +#: bottles/frontend/ui/details-versioning.blp:54 +msgid "A short comment" +msgstr "" + +#: bottles/frontend/ui/details-versioning.blp:58 +msgid "Save the bottle state." +msgstr "" + +#: bottles/frontend/ui/details-versioning.blp:78 +msgid "Create new Snapshot" +msgstr "" + +#: bottles/frontend/ui/details.blp:16 +msgid "Details" +msgstr "დეტალები" + +#: bottles/frontend/ui/details.blp:24 bottles/frontend/ui/details.blp:64 +#: bottles/frontend/ui/importer.blp:15 +msgid "Go Back" +msgstr "უკან დაბრუნება" + +#: bottles/frontend/ui/details.blp:75 +msgid "Operations" +msgstr "ოპერაციები" + +#: bottles/frontend/ui/dialog-bottle-picker.blp:4 +msgid "Select Bottle" +msgstr "" + +#: bottles/frontend/ui/dialog-bottle-picker.blp:16 +#: bottles/frontend/ui/dialog-proton-alert.blp:16 +#: bottles/frontend/ui/dialog-rename.blp:15 +#: bottles/frontend/ui/dialog-run-args.blp:20 +msgid "Cancel" +msgstr "გაუქმება" + +#: bottles/frontend/ui/dialog-bottle-picker.blp:21 +msgid "Select" +msgstr "არჩევა" + +#: bottles/frontend/ui/dialog-bottle-picker.blp:38 +#: bottles/frontend/ui/new.blp:9 bottles/frontend/ui/new.blp:49 +#: bottles/frontend/ui/window.blp:25 +msgid "Create New Bottle" +msgstr "" + +#: bottles/frontend/ui/dialog-crash-report.blp:8 +msgid "Bottles Crash Report" +msgstr "" + +#: bottles/frontend/ui/dialog-crash-report.blp:18 +#: bottles/frontend/ui/dialog-duplicate.blp:22 +#: bottles/frontend/ui/dialog-gamescope.blp:23 +#: bottles/frontend/ui/dialog-launch-options.blp:16 +#: bottles/frontend/ui/dialog-upgrade-versioning.blp:22 +#: bottles/frontend/ui/dialog-vkbasalt.blp:27 bottles/frontend/ui/new.blp:26 +#: bottles/frontend/views/bottle_details.py:507 +#: bottles/frontend/views/bottle_details.py:603 +#: bottles/frontend/views/bottle_preferences.py:746 +#: bottles/frontend/views/preferences.py:212 +msgid "_Cancel" +msgstr "_შეწყვეტა" + +#: bottles/frontend/ui/dialog-crash-report.blp:25 +msgid "Send Report" +msgstr "" + +#: bottles/frontend/ui/dialog-crash-report.blp:44 +msgid "" +"Bottles crashed last time. Please fill out a report attaching the following " +"traceback to help us identify the problem preventing it from happening again." +msgstr "" + +#: bottles/frontend/ui/dialog-crash-report.blp:74 +msgid "" +"We found one or more similar (or identical) reports. Please make sure to " +"check carefully that it has not already been reported before submitting a " +"new one. Each report requires effort on the part of the developers to " +"diagnose, please respect their work and make sure you don't post duplicates." +msgstr "" + +#: bottles/frontend/ui/dialog-crash-report.blp:89 +msgid "I still want to report." +msgstr "" + +#: bottles/frontend/ui/dialog-crash-report.blp:95 +msgid "Advanced options" +msgstr "დამატებითი პარამეტრები" + +#: bottles/frontend/ui/dialog-deps-check.blp:13 +msgid "Incomplete package" +msgstr "" + +#: bottles/frontend/ui/dialog-deps-check.blp:14 +msgid "" +"This version of Bottles does not seem to provide all the necessary core " +"dependencies, please contact the package maintainer or use an official " +"version." +msgstr "" + +#: bottles/frontend/ui/dialog-deps-check.blp:18 +msgid "Quit" +msgstr "გასვლა" + +#: bottles/frontend/ui/dialog-dll-overrides.blp:11 +msgid "" +"Dynamic Link Libraries can be specified to be builtin (provided by Wine) or " +"native (provided by the program)." +msgstr "" + +#: bottles/frontend/ui/dialog-dll-overrides.blp:15 +msgid "New Override" +msgstr "" + +#: bottles/frontend/ui/dialog-dll-overrides.blp:21 +msgid "Overrides" +msgstr "გადაფარავს" + +#: bottles/frontend/ui/dialog-drives.blp:7 +msgid "Drives" +msgstr "დისკები" + +#: bottles/frontend/ui/dialog-drives.blp:24 +msgid "" +"These are paths from your host system that are mapped and recognized as " +"devices by the runner (e.g. C: D:…)." +msgstr "" + +#: bottles/frontend/ui/dialog-drives.blp:27 +msgid "Letter" +msgstr "წერილი" + +#: bottles/frontend/ui/dialog-drives.blp:49 +msgid "Existing Drives" +msgstr "" + +#: bottles/frontend/ui/dialog-duplicate.blp:16 +msgid "Duplicate Bottle" +msgstr "" + +#: bottles/frontend/ui/dialog-duplicate.blp:38 +msgid "Duplicate" +msgstr "დუბლირება" + +#: bottles/frontend/ui/dialog-duplicate.blp:49 +msgid "Enter a name for the duplicate of the Bottle." +msgstr "" + +#: bottles/frontend/ui/dialog-duplicate.blp:69 +msgid "Duplicating…" +msgstr "დუბლირება…" + +#: bottles/frontend/ui/dialog-duplicate.blp:78 +#: bottles/frontend/ui/dialog-installer.blp:103 +#: bottles/frontend/ui/dialog-upgrade-versioning.blp:112 +#: bottles/frontend/views/new.py:177 +msgid "This could take a while." +msgstr "საკმაო დრო დასჭირდება." + +#: bottles/frontend/ui/dialog-duplicate.blp:97 +msgid "Bottle Duplicated" +msgstr "" + +#: bottles/frontend/ui/dialog-env-vars.blp:28 +msgid "" +"Environment variables are dynamic-named value that can affect the way " +"running processes will behave on your bottle." +msgstr "" + +#: bottles/frontend/ui/dialog-env-vars.blp:31 +msgid "Variable Name" +msgstr "ცვლადის სახელი" + +#: bottles/frontend/ui/dialog-env-vars.blp:37 +msgid "Existing Variables" +msgstr "" + +#: bottles/frontend/ui/dialog-exclusion-patterns.blp:20 +msgid "Exclusion Patterns" +msgstr "ამოღების ნიმუშები" + +#: bottles/frontend/ui/dialog-exclusion-patterns.blp:28 +msgid "" +"Define patterns that will be used to prevent some directories to being " +"versioned." +msgstr "" + +#: bottles/frontend/ui/dialog-exclusion-patterns.blp:31 +msgid "Pattern" +msgstr "შაბლონი" + +#: bottles/frontend/ui/dialog-exclusion-patterns.blp:37 +msgid "Existing Patterns" +msgstr "" + +#: bottles/frontend/ui/dialog-gamescope.blp:6 +msgid "Gamescope Settings" +msgstr "" + +#: bottles/frontend/ui/dialog-gamescope.blp:30 +#: bottles/frontend/ui/dialog-launch-options.blp:32 +#: bottles/frontend/ui/dialog-rename.blp:20 +#: bottles/frontend/ui/dialog-vkbasalt.blp:34 +msgid "Save" +msgstr "შენახვა" + +#: bottles/frontend/ui/dialog-gamescope.blp:40 +msgid "Manage how games should be displayed." +msgstr "" + +#: bottles/frontend/ui/dialog-gamescope.blp:44 +msgid "Game Resolution" +msgstr "" + +#: bottles/frontend/ui/dialog-gamescope.blp:45 +msgid "Uses the resolution of the video game as a reference in pixels." +msgstr "" + +#: bottles/frontend/ui/dialog-gamescope.blp:48 +#: bottles/frontend/ui/dialog-gamescope.blp:85 +msgid "Width" +msgstr "სიგანე" + +#: bottles/frontend/ui/dialog-gamescope.blp:64 +#: bottles/frontend/ui/dialog-gamescope.blp:101 +msgid "Height" +msgstr "სიმაღლე" + +#: bottles/frontend/ui/dialog-gamescope.blp:81 +msgid "Window Resolution" +msgstr "" + +#: bottles/frontend/ui/dialog-gamescope.blp:82 +msgid "" +"Upscales the resolution when using a resolution higher than the game " +"resolution in pixels." +msgstr "" + +#: bottles/frontend/ui/dialog-gamescope.blp:118 +msgid "Miscellaneous" +msgstr "სხვადასხვა" + +#: bottles/frontend/ui/dialog-gamescope.blp:121 +msgid "Frame Rate Limit" +msgstr "" + +#: bottles/frontend/ui/dialog-gamescope.blp:137 +msgid "Frame Rate Limit When Unfocused" +msgstr "" + +#: bottles/frontend/ui/dialog-gamescope.blp:153 +msgid "Integer Scaling" +msgstr "" + +#: bottles/frontend/ui/dialog-gamescope.blp:162 +msgid "Window Type" +msgstr "ფანჯრის ტიპი" + +#: bottles/frontend/ui/dialog-gamescope.blp:166 +msgid "Borderless" +msgstr "საზღვრების გარეშე" + +#: bottles/frontend/ui/dialog-gamescope.blp:172 +msgid "Fullscreen" +msgstr "სრულ ეკრანზე" + +#: bottles/frontend/ui/dialog-installer.blp:40 +msgid "Do you want to proceed with the installation?" +msgstr "" + +#: bottles/frontend/ui/dialog-installer.blp:45 +msgid "Start Installation" +msgstr "" + +#: bottles/frontend/ui/dialog-installer.blp:64 +msgid "" +"This installer requires some local resources which cannot be provided " +"otherwise." +msgstr "" + +#: bottles/frontend/ui/dialog-installer.blp:68 +msgid "Proceed" +msgstr "გაგრძელება" + +#: bottles/frontend/ui/dialog-installer.blp:127 +msgid "Completed!" +msgstr "დასრულდა!" + +#: bottles/frontend/ui/dialog-installer.blp:130 +msgid "Show Programs" +msgstr "" + +#: bottles/frontend/ui/dialog-installer.blp:148 +msgid "Installation Failed!" +msgstr "" + +#: bottles/frontend/ui/dialog-installer.blp:149 +msgid "Something went wrong." +msgstr "რაღაც მოხდა." + +#: bottles/frontend/ui/dialog-journal.blp:9 +msgid "All messages" +msgstr "ყველა შეტყობინება" + +#: bottles/frontend/ui/dialog-journal.blp:13 +msgid "Critical" +msgstr "კრიტიკული" + +#: bottles/frontend/ui/dialog-journal.blp:17 +msgid "Errors" +msgstr "შედომები" + +#: bottles/frontend/ui/dialog-journal.blp:21 +msgid "Warnings" +msgstr "გაფრთხილებები" + +#: bottles/frontend/ui/dialog-journal.blp:25 +msgid "Info" +msgstr "ინფორმაცია" + +#: bottles/frontend/ui/dialog-journal.blp:40 +#: bottles/frontend/ui/dialog-journal.blp:48 +msgid "Journal Browser" +msgstr "" + +#: bottles/frontend/ui/dialog-journal.blp:53 +msgid "Change Logging Level." +msgstr "" + +#: bottles/frontend/ui/dialog-journal.blp:57 +msgid "All" +msgstr "ყველა" + +#: bottles/frontend/ui/dialog-launch-options.blp:42 +msgid "Those arguments will be passed at launch." +msgstr "" + +#: bottles/frontend/ui/dialog-launch-options.blp:43 +msgid "Custom Arguments" +msgstr "" + +#: bottles/frontend/ui/dialog-launch-options.blp:46 +msgid "Command Arguments" +msgstr "ბრძანების არგუმენტები" + +#: bottles/frontend/ui/dialog-launch-options.blp:47 +#, c-format +msgid "e.g.: VAR=value %command% -example1 -example2 -example3=hello" +msgstr "" + +#: bottles/frontend/ui/dialog-launch-options.blp:52 +msgid "Post-run Script" +msgstr "" + +#. endregion +#: bottles/frontend/ui/dialog-launch-options.blp:53 +#: bottles/frontend/windows/launchoptions.py:53 +msgid "Choose a script which should be executed after run." +msgstr "" + +#: bottles/frontend/ui/dialog-launch-options.blp:70 +msgid "Choose a Script" +msgstr "" + +#: bottles/frontend/ui/dialog-launch-options.blp:84 +#: bottles/frontend/windows/launchoptions.py:54 +msgid "Choose from where start the program." +msgstr "" + +#: bottles/frontend/ui/dialog-launch-options.blp:101 +#: bottles/frontend/ui/drive-entry.blp:22 +msgid "Choose a Directory" +msgstr "" + +#: bottles/frontend/ui/dialog-launch-options.blp:114 +msgid "These settings will override the default settings for this executable." +msgstr "" + +#: bottles/frontend/ui/dialog-launch-options.blp:115 +msgid "Preferences Overrides" +msgstr "" + +#: bottles/frontend/ui/dialog-launch-options.blp:119 +msgid "Reset to Bottle's Defaults" +msgstr "" + +#: bottles/frontend/ui/dialog-launch-options.blp:165 +msgid "Virtual Desktop" +msgstr "ვირტუალური სამუშაო მაგიდა" + +#: bottles/frontend/ui/dialog-mangohud.blp:42 +msgid "Display On Game Start" +msgstr "" + +#: bottles/frontend/ui/dialog-mangohud.blp:43 +msgid "Display HUD as soon as the game starts. Can be toggled in-game (default keybind: [⇧ Right Shift] + [F12])." +msgstr "" + +#: bottles/frontend/ui/dialog-proton-alert.blp:4 +msgid "Proton Disclaimer" +msgstr "" + +#: bottles/frontend/ui/dialog-proton-alert.blp:21 +msgid "Use Proton" +msgstr "" + +#: bottles/frontend/ui/dialog-proton-alert.blp:35 +msgid "" +"Beware, using Proton-based runners in non-Steam bottles can cause problems " +"and prevent them from behaving correctly.\n" +"\n" +"We recommend using Wine-GE rather, a version of Proton meant to run outside " +"of Steam.\n" +"\n" +"Proceeding will automatically enable the Steam runtime (if present in the " +"system and detected by Bottles) in order to allow it to access the necessary " +"libraries and limit compatibility problems. Be aware that GloriousEggroll, " +"the runner's provider, is not responsible for any problems and we ask that " +"you do not report to them." +msgstr "" + +#: bottles/frontend/ui/dialog-proton-alert.blp:43 +msgid "I got it." +msgstr "" + +#: bottles/frontend/ui/dialog-rename.blp:7 +msgid "Rename" +msgstr "სახელის გადარქმევა" + +#: bottles/frontend/ui/dialog-rename.blp:30 +msgid "Choose a new name for the selected program." +msgstr "" + +#: bottles/frontend/ui/dialog-rename.blp:33 +msgid "New Name" +msgstr "ახალი სახელი" + +#: bottles/frontend/ui/dialog-run-args.blp:13 +msgid "Run With Arguments" +msgstr "" + +#: bottles/frontend/ui/dialog-run-args.blp:34 +#: bottles/frontend/views/bottle_details.py:404 +#: bottles/frontend/views/list.py:131 +msgid "Run" +msgstr "გაშვება" + +#: bottles/frontend/ui/dialog-run-args.blp:44 +msgid "Write below the arguments to be passed to the executable." +msgstr "" + +#: bottles/frontend/ui/dialog-run-args.blp:47 +msgid "e.g.: -opengl -SkipBuildPatchPrereq" +msgstr "" + +#: bottles/frontend/ui/dialog-sandbox.blp:7 +msgid "Sandbox Settings" +msgstr "" + +#: bottles/frontend/ui/dialog-sandbox.blp:25 +msgid "Share Network" +msgstr "ქსელის გაზიარება" + +#: bottles/frontend/ui/dialog-sandbox.blp:34 +msgid "Share Sound" +msgstr "" + +#: bottles/frontend/ui/dialog-upgrade-versioning.blp:16 +msgid "Upgrade Needed" +msgstr "" + +#: bottles/frontend/ui/dialog-upgrade-versioning.blp:38 +#: bottles/frontend/ui/onboard.blp:81 +msgid "Continue" +msgstr "გაგრძელება" + +#: bottles/frontend/ui/dialog-upgrade-versioning.blp:47 +msgid "Launch upgrade" +msgstr "" + +#: bottles/frontend/ui/dialog-upgrade-versioning.blp:66 +msgid "New Versioning System" +msgstr "" + +#: bottles/frontend/ui/dialog-upgrade-versioning.blp:69 +msgid "The new bottle versioning system has landed." +msgstr "" + +#: bottles/frontend/ui/dialog-upgrade-versioning.blp:83 +msgid "" +"Bottles has a whole new Versioning System that is not backwards compatible.\n" +"\n" +"To continue using versioning we need to re-initialize the bottle repository. " +"This will not delete data from your bottle but will delete all existing " +"snapshots and create a new one.\n" +"\n" +"If you need to go back to a previous snapshot before continuing, close this " +"window and restore the snapshot, then reopen the bottle to show this window " +"again.\n" +"\n" +"The old system will be discontinued in one of the next releases." +msgstr "" + +#: bottles/frontend/ui/dialog-upgrade-versioning.blp:103 +msgid "Re-initializing Repository…" +msgstr "" + +#: bottles/frontend/ui/dialog-upgrade-versioning.blp:133 +msgid "Done! Please restart Bottles." +msgstr "" + +#. Translators: vkBasalt is a Vulkan post processing layer for Linux +#: bottles/frontend/ui/dialog-vkbasalt.blp:10 +msgid "Post-Processing Effects Settings" +msgstr "" + +#: bottles/frontend/ui/dialog-vkbasalt.blp:44 +msgid "Default" +msgstr "ნაგულისხმევი" + +#: bottles/frontend/ui/dialog-vkbasalt.blp:48 +msgid "Default Settings" +msgstr "ნაგულისხმევი პარამეტრები" + +#: bottles/frontend/ui/dialog-vkbasalt.blp:57 +msgid "Effects are applied according to the list order." +msgstr "" + +#: bottles/frontend/ui/dialog-vkbasalt.blp:58 +msgid "Effects" +msgstr "ეფექტები" + +#: bottles/frontend/ui/dialog-vkbasalt.blp:62 +msgid "Contrast Adaptive Sharpening" +msgstr "" + +#: bottles/frontend/ui/dialog-vkbasalt.blp:65 +#: bottles/frontend/ui/dialog-vkbasalt.blp:102 +msgid "Sharpness" +msgstr "სიმკვეთრე" + +#: bottles/frontend/ui/dialog-vkbasalt.blp:69 +#: bottles/frontend/ui/dialog-vkbasalt.blp:106 +#: bottles/frontend/ui/dialog-vkbasalt.blp:134 +#: bottles/frontend/ui/dialog-vkbasalt.blp:167 +#: bottles/frontend/ui/dialog-vkbasalt.blp:195 +#: bottles/frontend/ui/dialog-vkbasalt.blp:223 +#: bottles/frontend/ui/dialog-vkbasalt.blp:256 +#: bottles/frontend/ui/dialog-vkbasalt.blp:288 +#: bottles/frontend/ui/dialog-vkbasalt.blp:316 +#: bottles/frontend/ui/dialog-vkbasalt.blp:343 +#: bottles/frontend/ui/dialog-vkbasalt.blp:370 bottles/frontend/ui/new.blp:58 +msgid "Show Information" +msgstr "ინფორმაციის ჩვენება" + +#. Translators: Luma is not translatable +#: bottles/frontend/ui/dialog-vkbasalt.blp:99 +msgid "Denoised Luma Sharpening" +msgstr "" + +#: bottles/frontend/ui/dialog-vkbasalt.blp:130 +msgid "Denoise" +msgstr "ხმაურის მოცილება" + +#: bottles/frontend/ui/dialog-vkbasalt.blp:160 +msgid "Fast Approximate Anti-Aliasing" +msgstr "" + +#: bottles/frontend/ui/dialog-vkbasalt.blp:163 +msgid "Subpixel Quality" +msgstr "" + +#: bottles/frontend/ui/dialog-vkbasalt.blp:191 +msgid "Quality Edge Threshold" +msgstr "" + +#: bottles/frontend/ui/dialog-vkbasalt.blp:219 +msgid "Quality Edge Threshold Minimum" +msgstr "" + +#: bottles/frontend/ui/dialog-vkbasalt.blp:249 +msgid "Subpixel Morphological Anti-Aliasing" +msgstr "" + +#: bottles/frontend/ui/dialog-vkbasalt.blp:252 +msgid "Edge Detection" +msgstr "" + +#: bottles/frontend/ui/dialog-vkbasalt.blp:267 +msgid "Luma" +msgstr "ლუმა" + +#: bottles/frontend/ui/dialog-vkbasalt.blp:273 +msgid "Color" +msgstr "ფერი" + +#: bottles/frontend/ui/dialog-vkbasalt.blp:284 +msgid "Threshold" +msgstr "ზღვარი" + +#: bottles/frontend/ui/dialog-vkbasalt.blp:312 +msgid "Max Search Steps" +msgstr "" + +#: bottles/frontend/ui/dialog-vkbasalt.blp:339 +msgid "Max Search Steps Diagonal" +msgstr "" + +#: bottles/frontend/ui/dialog-vkbasalt.blp:366 +msgid "Max Corner Rounding" +msgstr "" + +#: bottles/frontend/ui/dialog-vkbasalt.blp:411 +msgid "" +"CAS sharpness increases the sharpness of a frame. Higher values make the " +"frame sharper, whereas values lower than 0 make the frame softer than native." +msgstr "" + +#: bottles/frontend/ui/dialog-vkbasalt.blp:428 +msgid "" +"DLS sharpness increases the sharpness of a frame. Higher values make the " +"frame sharper." +msgstr "" + +#: bottles/frontend/ui/dialog-vkbasalt.blp:445 +msgid "" +"DLS denoise decreases the noise of a frame. Higher values make the frame " +"softer." +msgstr "" + +#: bottles/frontend/ui/dialog-vkbasalt.blp:462 +msgid "" +"FXAA subpixel quality decreases aliasing at the subpixel level. Higher " +"values make the frame softer." +msgstr "" + +#: bottles/frontend/ui/dialog-vkbasalt.blp:479 +msgid "" +"FXAA edge threshold is the minimum amount of contrast required to apply the " +"FXAA algorithm. Higher values make the frame have more contrast." +msgstr "" + +#: bottles/frontend/ui/dialog-vkbasalt.blp:496 +msgid "" +"FXAA quality edge threshold minimum is the minimum value of dark pixels that " +"are ignored by the FXAA algorithm. Higher values make FXAA ignore pixels " +"below the specified value and can lead to a performance increase." +msgstr "" + +#: bottles/frontend/ui/dialog-vkbasalt.blp:513 +msgid "" +"Luma detects edges from a monochrome perspective, whereas Color detects " +"edges based on colors. Luma is more performant than Color." +msgstr "" + +#: bottles/frontend/ui/dialog-vkbasalt.blp:530 +msgid "" +"SMAA threshold specifies the sensitivity of edge detection. Lower values " +"detect more edges at the expense of performance." +msgstr "" + +#: bottles/frontend/ui/dialog-vkbasalt.blp:547 +msgid "" +"SMAA max search steps specifies how many horizontal and vertical search " +"steps are performed when searching for edges." +msgstr "" + +#: bottles/frontend/ui/dialog-vkbasalt.blp:564 +msgid "" +"SMAA max diagonal search steps specifies how many diagonal search steps are " +"performed when searching for edges." +msgstr "" + +#: bottles/frontend/ui/dialog-vkbasalt.blp:581 +msgid "SMAA corner rounding specifies the strength of rounding edge corners." +msgstr "" + +#: bottles/frontend/ui/dll-override-entry.blp:8 +msgid "Builtin (Wine)" +msgstr "" + +#: bottles/frontend/ui/dll-override-entry.blp:9 +msgid "Native (Windows)" +msgstr "" + +#: bottles/frontend/ui/dll-override-entry.blp:10 +msgid "Builtin, then Native" +msgstr "" + +#: bottles/frontend/ui/dll-override-entry.blp:11 +msgid "Native, then Builtin" +msgstr "" + +#: bottles/frontend/ui/dll-override-entry.blp:12 +msgid "Disabled" +msgstr "გამორთული" + +#: bottles/frontend/ui/dll-override-entry.blp:20 +#: bottles/frontend/ui/drive-entry.blp:12 +msgid "Remove" +msgstr "წაშლა" + +#: bottles/frontend/ui/drive-entry.blp:5 +msgid "/point/to/path" +msgstr "/ბილიკი/წერტილამდე" + +#: bottles/frontend/ui/env-var-entry.blp:4 +#: bottles/frontend/ui/exclusion-pattern-entry.blp:4 +msgid "Value" +msgstr "მნიშვნელობა" + +#. Translators: A Wine prefix is a separate environment (C:\ drive) for the Wine program +#: bottles/frontend/ui/importer-entry.blp:21 +msgid "Wine prefix name" +msgstr "" + +#: bottles/frontend/ui/importer-entry.blp:28 +msgid "Manager" +msgstr "მმართველი" + +#: bottles/frontend/ui/importer-entry.blp:38 +msgid "This Wine prefix was already imported in Bottles." +msgstr "" + +#: bottles/frontend/ui/importer.blp:22 +msgid "Import a Bottle backup" +msgstr "" + +#: bottles/frontend/ui/importer.blp:28 +msgid "Search again for prefixes" +msgstr "" + +#: bottles/frontend/ui/importer.blp:38 +msgid "No Prefixes Found" +msgstr "" + +#: bottles/frontend/ui/importer.blp:39 +msgid "" +"No external prefixes were found. Does Bottles have access to them?\n" +"Use the icon on the top to import a bottle from a backup." +msgstr "" + +#: bottles/frontend/ui/importer.blp:74 +msgid "Full Archive" +msgstr "" + +#: bottles/frontend/ui/installer-entry.blp:16 +msgid "Show Manifest…" +msgstr "" + +#: bottles/frontend/ui/installer-entry.blp:20 +msgid "Read Review…" +msgstr "" + +#: bottles/frontend/ui/installer-entry.blp:34 +msgid "Installer name" +msgstr "დამყენებლის სახელი" + +#: bottles/frontend/ui/installer-entry.blp:35 +msgid "Installer description" +msgstr "" + +#: bottles/frontend/ui/installer-entry.blp:42 +msgid "Unknown" +msgstr "უცნობი" + +#: bottles/frontend/ui/installer-entry.blp:51 +msgid "Install this Program" +msgstr "" + +#: bottles/frontend/ui/installer-entry.blp:69 +msgid "Program Menu" +msgstr "" + +#: bottles/frontend/ui/library-entry.blp:33 +msgid "No Thumbnail" +msgstr "" + +#: bottles/frontend/ui/library-entry.blp:57 +msgid "Launch" +msgstr "გაშვება" + +#: bottles/frontend/ui/library-entry.blp:70 +#: bottles/frontend/ui/program-entry.blp:89 +msgid "Launch with Steam" +msgstr "" + +#: bottles/frontend/ui/library-entry.blp:108 +msgid "Item name" +msgstr "ჩანაწერის სახელი" + +#: bottles/frontend/ui/library-entry.blp:132 +msgid "Remove from Library" +msgstr "" + +#: bottles/frontend/ui/library-entry.blp:143 +msgid "Stop" +msgstr "შეჩერება" + +#: bottles/frontend/ui/library.blp:11 +#: bottles/frontend/windows/main_window.py:196 +msgid "Library" +msgstr "ბიბლიოთეკა" + +#: bottles/frontend/ui/library.blp:12 +msgid "Add items here from your bottle's program list" +msgstr "" + +#: bottles/frontend/ui/list-entry.blp:26 +msgid "Versioning is active in this bottle." +msgstr "" + +#: bottles/frontend/ui/list-entry.blp:42 +msgid "This bottle looks damaged." +msgstr "" + +#: bottles/frontend/ui/list-entry.blp:55 +msgid "Execute in this Bottle" +msgstr "" + +#: bottles/frontend/ui/list-entry.blp:69 +msgid "Run Here" +msgstr "" + +#: bottles/frontend/ui/list-entry.blp:75 +msgid "" +"This bottle looks damaged, the configuration file is missing. I can try to " +"solve by creating a new configuration." +msgstr "" + +#: bottles/frontend/ui/list.blp:12 +msgid "Search your bottles…" +msgstr "" + +#: bottles/frontend/ui/list.blp:28 +msgid "Steam Proton" +msgstr "" + +#: bottles/frontend/ui/list.blp:42 bottles/frontend/windows/main_window.py:191 +#: data/com.usebottles.bottles.metainfo.xml.in:7 +msgid "Bottles" +msgstr "Bottles" + +#: bottles/frontend/ui/list.blp:49 +msgid "Create New Bottle…" +msgstr "" + +#: bottles/frontend/ui/list.blp:63 +msgid "No Results Found" +msgstr "შედეგების გარეშე" + +#: bottles/frontend/ui/list.blp:64 +msgid "Try a different search." +msgstr "სცადეთ სხვა ძებნა." + +#: bottles/frontend/ui/loading.blp:13 +msgid "Starting up…" +msgstr "გაშვება…" + +#: bottles/frontend/ui/loading.blp:22 +msgid "Continue Offline" +msgstr "" + +#: bottles/frontend/ui/local-resource-entry.blp:4 +msgid "This resource is missing." +msgstr "" + +#: bottles/frontend/ui/local-resource-entry.blp:8 +msgid "Browse" +msgstr "პოვნა" + +#: bottles/frontend/ui/new.blp:32 +msgid "C_reate" +msgstr "_შექმნა" + +#: bottles/frontend/ui/new.blp:75 +msgid "_Application" +msgstr "_აპლიკაცია" + +#: bottles/frontend/ui/new.blp:88 +msgid "_Gaming" +msgstr "_თამაშები" + +#: bottles/frontend/ui/new.blp:101 +msgid "C_ustom" +msgstr "მორგებ_ული" + +#: bottles/frontend/ui/new.blp:114 +msgid "Custom" +msgstr "მომხმარებლის" + +#: bottles/frontend/ui/new.blp:118 +msgid "Share User Directory" +msgstr "" + +#: bottles/frontend/ui/new.blp:119 +msgid "" +"This makes the user directory discoverable in the bottle, at the risk of " +"sharing personal information to Windows software. This option cannot be " +"changed after the bottle has been created." +msgstr "" + +#: bottles/frontend/ui/new.blp:136 +msgid "Architecture" +msgstr "არქიტექტურა" + +#: bottles/frontend/ui/new.blp:137 +msgid "32-bit should only be used if strictly necessary." +msgstr "" + +#: bottles/frontend/ui/new.blp:146 +msgid "Import a custom configuration." +msgstr "" + +#: bottles/frontend/ui/new.blp:176 +msgid "Bottle Directory" +msgstr "" + +#: bottles/frontend/ui/new.blp:177 +msgid "Directory that will contain the data of this bottle." +msgstr "" + +#: bottles/frontend/ui/new.blp:249 +msgid "_Close" +msgstr "და_ხურვა" + +#: bottles/frontend/ui/new.blp:281 +msgid "This name is unavailable, please try another." +msgstr "" + +#: bottles/frontend/ui/onboard.blp:34 +msgid "Previous" +msgstr "წინა" + +#: bottles/frontend/ui/onboard.blp:59 +msgid "Welcome to Bottles" +msgstr "" + +#: bottles/frontend/ui/onboard.blp:60 +msgid "Run Windows Software on Linux." +msgstr "" + +#: bottles/frontend/ui/onboard.blp:65 +msgid "Windows in Bottles" +msgstr "" + +#: bottles/frontend/ui/onboard.blp:66 +msgid "" +"Bottles uses compatibility runners to provide isolated containerized Windows-" +"like environments where programs run." +msgstr "" + +#: bottles/frontend/ui/onboard.blp:72 +msgid "Almost Done" +msgstr "" + +#: bottles/frontend/ui/onboard.blp:73 +msgid "We need a few more minutes to set everything up…" +msgstr "" + +#: bottles/frontend/ui/onboard.blp:105 +msgid "All Ready!" +msgstr "" + +#: bottles/frontend/ui/onboard.blp:114 +msgid "Please Finish the setup first" +msgstr "" + +#: bottles/frontend/ui/onboard.blp:120 +msgid "Start using Bottles" +msgstr "" + +#: bottles/frontend/ui/onboard.blp:141 +msgid "Next" +msgstr "შემდეგი" + +#: bottles/frontend/ui/preferences.blp:5 bottles/frontend/ui/window.blp:86 +msgid "Preferences" +msgstr "მორგება" + +#: bottles/frontend/ui/preferences.blp:12 +#: bottles/frontend/ui/preferences.blp:40 +msgid "General" +msgstr "ზოგადი" + +#: bottles/frontend/ui/preferences.blp:15 +msgid "Appearance" +msgstr "გარეგნობა" + +#: bottles/frontend/ui/preferences.blp:18 +msgid "Dark Mode" +msgstr "მუქი რეჟიმი" + +#: bottles/frontend/ui/preferences.blp:19 +msgid "Whether Bottles should use the dark color scheme." +msgstr "" + +#: bottles/frontend/ui/preferences.blp:29 +msgid "Show Update Date" +msgstr "" + +#: bottles/frontend/ui/preferences.blp:30 +msgid "Whether to show the update date in the bottle list." +msgstr "" + +#: bottles/frontend/ui/preferences.blp:43 +#: data/com.usebottles.bottles.gschema.xml:51 +msgid "Notifications" +msgstr "გაფრთხილებები" + +#: bottles/frontend/ui/preferences.blp:44 +msgid "Show notifications for downloads and installs." +msgstr "" + +#: bottles/frontend/ui/preferences.blp:53 +msgid "Temp Files" +msgstr "" + +#: bottles/frontend/ui/preferences.blp:54 +msgid "Clean temp files when Bottles launches?" +msgstr "" + +#: bottles/frontend/ui/preferences.blp:63 +msgid "Close Bottles After Starting a Program" +msgstr "" + +#: bottles/frontend/ui/preferences.blp:64 +msgid "Close Bottles after starting a program from the file manager." +msgstr "" + +#: bottles/frontend/ui/preferences.blp:74 +msgid "Integrations" +msgstr "ინტეგრაციები" + +#: bottles/frontend/ui/preferences.blp:77 +msgid "Steam Proton Prefixes" +msgstr "" + +#: bottles/frontend/ui/preferences.blp:78 +msgid "List and manage Steam Proton prefixes." +msgstr "" + +#: bottles/frontend/ui/preferences.blp:98 +msgid "List Steam Apps in Programs List" +msgstr "" + +#: bottles/frontend/ui/preferences.blp:99 +msgid "Requires Steam for Windows installed in the bottle." +msgstr "" + +#: bottles/frontend/ui/preferences.blp:108 +msgid "List Epic Games in Programs List" +msgstr "" + +#: bottles/frontend/ui/preferences.blp:109 +msgid "Requires Epic Games Store installed in the bottle." +msgstr "" + +#: bottles/frontend/ui/preferences.blp:118 +msgid "List Ubisoft Games in Programs List" +msgstr "" + +#: bottles/frontend/ui/preferences.blp:119 +msgid "Requires Ubisoft Connect installed in the bottle." +msgstr "" + +#: bottles/frontend/ui/preferences.blp:129 +msgid "Advanced" +msgstr "დამატებით" + +#: bottles/frontend/ui/preferences.blp:132 +msgid "Pre-Release" +msgstr "პრერელიზი" + +#: bottles/frontend/ui/preferences.blp:133 +msgid "Display unstable versions of runners and components." +msgstr "" + +#: bottles/frontend/ui/preferences.blp:142 +msgid "Force Offline Mode" +msgstr "" + +#: bottles/frontend/ui/preferences.blp:143 +msgid "" +"Force disable any network activity even with available network connection." +msgstr "" + +#: bottles/frontend/ui/preferences.blp:152 +msgid "Bottles Directory" +msgstr "" + +#: bottles/frontend/ui/preferences.blp:153 +msgid "Directory that contains the data of your Bottles." +msgstr "" + +#: bottles/frontend/ui/preferences.blp:188 +msgid "Runners" +msgstr "გამშვებები" + +#: bottles/frontend/ui/preferences.blp:202 +msgid "Bottles is running in offline mode, so runners are not available." +msgstr "" + +#: bottles/frontend/ui/preferences.blp:236 +msgid "DLL Components" +msgstr "" + +#: bottles/frontend/ui/preferences.blp:250 +msgid "Bottles is running in offline mode, so DLLs are not available." +msgstr "" + +#: bottles/frontend/ui/preferences.blp:282 +msgid "DXVK-NVAPI" +msgstr "DXVK-NVAPI" + +#: bottles/frontend/ui/preferences.blp:295 +msgid "Core" +msgstr "ძირითადი ბირთვული მოდულები" + +#: bottles/frontend/ui/preferences.blp:299 +msgid "Runtime" +msgstr "გაშვების დრო" + +#: bottles/frontend/ui/preferences.blp:303 +msgid "WineBridge" +msgstr "WineBridge" + +#: bottles/frontend/ui/preferences.blp:309 +#: data/com.usebottles.bottles.gschema.xml:71 +msgid "Experiments" +msgstr "ექსპერიმენტები" + +#: bottles/frontend/ui/preferences.blp:312 +msgid "" +"These features are under heavy development and may be unstable, expect bugs " +"and breakage." +msgstr "" + +#: bottles/frontend/ui/preferences.blp:315 +msgid "Sandbox per bottle" +msgstr "" + +#: bottles/frontend/ui/preferences.blp:316 +msgid "In early development." +msgstr "" + +#: bottles/frontend/ui/program-entry.blp:19 +msgid "Launch with Terminal" +msgstr "" + +#: bottles/frontend/ui/program-entry.blp:25 +msgid "Browse Path" +msgstr "" + +#: bottles/frontend/ui/program-entry.blp:39 +msgid "Change Launch Options…" +msgstr "" + +#: bottles/frontend/ui/program-entry.blp:43 +msgid "Add to Library" +msgstr "" + +#: bottles/frontend/ui/program-entry.blp:47 +msgid "Add Desktop Entry" +msgstr "" + +#: bottles/frontend/ui/program-entry.blp:51 +msgid "Add to Steam" +msgstr "" + +#: bottles/frontend/ui/program-entry.blp:55 +msgid "Rename…" +msgstr "სახელის გადარქმევა…" + +#: bottles/frontend/ui/program-entry.blp:62 +msgid "Hide Program" +msgstr "" + +#: bottles/frontend/ui/program-entry.blp:66 +msgid "Show Program" +msgstr "" + +#: bottles/frontend/ui/program-entry.blp:70 +msgid "Remove from List" +msgstr "" + +#: bottles/frontend/ui/program-entry.blp:83 +msgid "Program name" +msgstr "" + +#. Translators: id as identification +#: bottles/frontend/ui/state-entry.blp:8 +msgid "State id" +msgstr "" + +#: bottles/frontend/ui/state-entry.blp:9 +msgid "State comment" +msgstr "" + +#: bottles/frontend/ui/state-entry.blp:16 +msgid "Restore this Snapshot" +msgstr "" + +#: bottles/frontend/ui/task-entry.blp:19 +msgid "Delete message" +msgstr "შეტყობინების წაშლა" + +#: bottles/frontend/ui/window.blp:40 +msgid "Main Menu" +msgstr "მთავარი მენიუ" + +#: bottles/frontend/ui/window.blp:54 +msgid "" +"You don't seem connected to the internet. Without it you will not be able to " +"download essential components. Click this icon when you have reestablished " +"the connection." +msgstr "" + +#: bottles/frontend/ui/window.blp:79 +msgid "Import…" +msgstr "შემოტანა…" + +#: bottles/frontend/ui/window.blp:91 +msgid "Help" +msgstr "დახმარება" + +#: bottles/frontend/ui/window.blp:96 +msgid "About Bottles" +msgstr "" + +#: bottles/frontend/views/bottle_details.py:193 +#, python-brace-format +msgid "File \"{0}\" is not a .exe or .msi file" +msgstr "" + +#: bottles/frontend/views/bottle_details.py:209 +#, python-format +msgid "Updated: %s" +msgstr "განახლებულია: %s" + +#: bottles/frontend/views/bottle_details.py:270 +#, python-brace-format +msgid "\"{0}\" added" +msgstr "" + +#: bottles/frontend/views/bottle_details.py:273 +#: bottles/frontend/views/bottle_details.py:401 +#: bottles/frontend/views/list.py:128 +msgid "Select Executable" +msgstr "" + +#: bottles/frontend/views/bottle_details.py:276 +msgid "Add" +msgstr "დამატება" + +#: bottles/frontend/views/bottle_details.py:349 +msgid "Hide Hidden Programs" +msgstr "" + +#: bottles/frontend/views/bottle_details.py:386 +#: bottles/frontend/widgets/library.py:163 +#: bottles/frontend/widgets/program.py:184 +#, python-brace-format +msgid "Launching \"{0}\"…" +msgstr "" + +#: bottles/frontend/views/bottle_details.py:416 +msgid "Be Aware of Sandbox" +msgstr "" + +#: bottles/frontend/views/bottle_details.py:417 +msgid "" +"Bottles is running in a sandbox, a restricted permission environment needed " +"to keep you safe. If the program won't run, consider moving inside the " +"bottle (3 dots icon on the top), then launch from there." +msgstr "" + +#: bottles/frontend/views/bottle_details.py:419 +#: bottles/frontend/views/bottle_details.py:528 +#: bottles/frontend/windows/main_window.py:223 +msgid "_Dismiss" +msgstr "_მოცილება" + +#: bottles/frontend/views/bottle_details.py:432 +msgid "Select the location where to save the backup config" +msgstr "" + +#: bottles/frontend/views/bottle_details.py:434 +msgid "Export" +msgstr "გატანა" + +#: bottles/frontend/views/bottle_details.py:436 +msgid "Select the location where to save the backup archive" +msgstr "" + +#: bottles/frontend/views/bottle_details.py:438 +msgid "Backup" +msgstr "მარქაფი" + +#: bottles/frontend/views/bottle_details.py:443 +#, python-brace-format +msgid "Backup created for \"{0}\"" +msgstr "" + +#: bottles/frontend/views/bottle_details.py:445 +#, python-brace-format +msgid "Backup failed for \"{0}\"" +msgstr "" + +#: bottles/frontend/views/bottle_details.py:504 +msgid "Are you sure you want to permanently delete \"{}\"?" +msgstr "" + +#: bottles/frontend/views/bottle_details.py:505 +msgid "" +"This will permanently delete all programs and settings associated with it." +msgstr "" + +#: bottles/frontend/views/bottle_details.py:508 +#: bottles/frontend/views/bottle_preferences.py:747 +msgid "_Delete" +msgstr "_წაშლა" + +#: bottles/frontend/views/bottle_details.py:524 +msgid "Missing Runner" +msgstr "" + +#: bottles/frontend/views/bottle_details.py:525 +msgid "" +"The runner requested by this bottle is missing. Install it through the " +"Bottles preferences or choose a new one to run applications." +msgstr "" + +#: bottles/frontend/views/bottle_details.py:600 +msgid "Are you sure you want to force stop all processes?" +msgstr "" + +#: bottles/frontend/views/bottle_details.py:601 +msgid "This can cause data loss, corruption, and programs to malfunction." +msgstr "" + +#: bottles/frontend/views/bottle_details.py:604 +msgid "Force _Stop" +msgstr "ძალით _გაჩერება" + +#: bottles/frontend/views/bottle_preferences.py:195 +msgid "This feature is unavailable on your system." +msgstr "" + +#: bottles/frontend/views/bottle_preferences.py:196 +msgid "{} To add this feature, please run flatpak install" +msgstr "" + +#: bottles/frontend/views/bottle_preferences.py:246 +msgid "This bottle name is already in use." +msgstr "" + +#: bottles/frontend/views/bottle_preferences.py:301 +#: bottles/frontend/windows/launchoptions.py:240 +msgid "Select Working Directory" +msgstr "აირჩიეთ სამუშაო საქაღალდე" + +#: bottles/frontend/views/bottle_preferences.py:422 +msgid "Directory that contains the data of \"{}\"." +msgstr "" + +#: bottles/frontend/views/bottle_preferences.py:743 +msgid "Are you sure you want to delete all snapshots?" +msgstr "" + +#: bottles/frontend/views/bottle_preferences.py:744 +msgid "This will delete all snapshots but keep your files." +msgstr "" + +#: bottles/frontend/views/bottle_versioning.py:90 +msgid "Please migrate to the new Versioning system to create new states." +msgstr "" + +#: bottles/frontend/views/details.py:153 +msgid "Installers" +msgstr "დაყენების პროგრამები" + +#: bottles/frontend/views/details.py:234 +msgid "Operations in progress, please wait." +msgstr "" + +#: bottles/frontend/views/details.py:239 +msgid "Return to your bottles." +msgstr "" + +#: bottles/frontend/views/importer.py:92 +msgid "Backup imported successfully" +msgstr "" + +#: bottles/frontend/views/importer.py:94 +msgid "Import failed" +msgstr "შემოტანა ჩავარდა" + +#: bottles/frontend/views/importer.py:108 +#: bottles/frontend/views/importer.py:145 +msgid "Importing backup…" +msgstr "" + +#: bottles/frontend/views/importer.py:117 +msgid "Select a Backup Archive" +msgstr "" + +#: bottles/frontend/views/importer.py:120 +#: bottles/frontend/views/importer.py:157 +msgid "Import" +msgstr "შემოტანა" + +#: bottles/frontend/views/importer.py:154 bottles/frontend/views/new.py:136 +msgid "Select a Configuration File" +msgstr "" + +#: bottles/frontend/views/list.py:60 bottles/frontend/views/list.py:66 +msgid "N/A" +msgstr "ა/მ" + +#. Set tooltip text +#: bottles/frontend/views/list.py:91 +#, python-brace-format +msgid "Run executable in \"{self.config.Name}\"" +msgstr "" + +#: bottles/frontend/views/list.py:118 +#, python-brace-format +msgid "Launching \"{0}\" in \"{1}\"…" +msgstr "" + +#: bottles/frontend/views/list.py:235 +msgid "Your Bottles" +msgstr "" + +#: bottles/frontend/views/loading.py:46 +#, python-brace-format +msgid "Downloading ~{0} of packages…" +msgstr "" + +#: bottles/frontend/views/loading.py:47 +#, python-brace-format +msgid "Fetched {0} of {1} packages" +msgstr "" + +#: bottles/frontend/views/new.py:157 +msgid "Select Bottle Directory" +msgstr "" + +#: bottles/frontend/views/new.py:176 +msgid "Creating Bottle…" +msgstr "" + +#: bottles/frontend/views/new.py:221 +msgid "Unable to Create Bottle" +msgstr "" + +#: bottles/frontend/views/new.py:225 +msgid "Bottle failed to create with one or more errors." +msgstr "" + +#. Show success +#: bottles/frontend/views/new.py:232 +msgid "Bottle Created" +msgstr "" + +#: bottles/frontend/views/new.py:233 +#, python-brace-format +msgid "\"{0}\" was created successfully." +msgstr "" + +#: bottles/frontend/views/preferences.py:134 +msgid "Steam was not found or Bottles does not have enough permissions." +msgstr "" + +#: bottles/frontend/views/preferences.py:187 +msgid "Select Bottles Path" +msgstr "" + +#: bottles/frontend/views/preferences.py:209 +msgid "Relaunch Bottles?" +msgstr "" + +#: bottles/frontend/views/preferences.py:210 +msgid "" +"Bottles will need to be relaunched to use this directory.\n" +"\n" +"Be sure to close every program launched from Bottles before relaunching " +"Bottles, as not doing so can cause data loss, corruption and programs to " +"malfunction." +msgstr "" + +#: bottles/frontend/views/preferences.py:213 +msgid "_Relaunch" +msgstr "_თავიდან გაშვება" + +#: bottles/frontend/views/preferences.py:306 +msgid "Based on Valve's Wine, includes Staging and Proton patches." +msgstr "" + +#: bottles/frontend/views/preferences.py:307 +msgid "Based on Wine upstream, includes Staging and Proton patches." +msgstr "" + +#: bottles/frontend/views/preferences.py:308 +msgid "" +"Based on the most recent bleeding-edge Valve's Proton Experimental Wine, " +"includes Staging and custom patches. This is meant to be used with non-steam " +"games outside of Steam." +msgstr "" + +#: bottles/frontend/views/preferences.py:311 +msgid "" +"Based on Wine upstream, Staging, Staging-TkG and Proton patchset optionally " +"available." +msgstr "" + +#: bottles/frontend/views/preferences.py:313 +msgid "Based on Wine upstream, includes Staging patches." +msgstr "" + +#: bottles/frontend/views/preferences.py:314 +msgid "" +"Based on most recent bleeding-edge Valve's Proton Experimental, includes " +"Staging and custom patches. Requires the Steam Runtime turned on." +msgstr "" + +#: bottles/frontend/views/preferences.py:317 +msgid "Other Wine runners" +msgstr "" + +#: bottles/frontend/views/preferences.py:318 +msgid "Other Proton runners" +msgstr "" + +#: bottles/frontend/widgets/component.py:76 +msgid "Upgrade" +msgstr "განახლება" + +#: bottles/frontend/widgets/component.py:142 +msgid "Installing…" +msgstr "დაყენება…" + +#: bottles/frontend/widgets/dependency.py:107 +#: bottles/frontend/widgets/installer.py:81 +#, python-brace-format +msgid "Manifest for {0}" +msgstr "" + +#: bottles/frontend/widgets/dependency.py:172 +#, python-brace-format +msgid "\"{0}\" uninstalled" +msgstr "" + +#: bottles/frontend/widgets/dependency.py:174 +#, python-brace-format +msgid "\"{0}\" installed" +msgstr "" + +#: bottles/frontend/widgets/dependency.py:188 +#, python-brace-format +msgid "\"{0}\" failed to install" +msgstr "" + +#: bottles/frontend/widgets/importer.py:68 +#, python-brace-format +msgid "\"{0}\" imported" +msgstr "" + +#: bottles/frontend/widgets/installer.py:49 +msgid "" +"This application may work poorly. The installer was configured to provide " +"the best possible experience, but expect glitches, instability and lack of " +"working features." +msgstr "" + +#: bottles/frontend/widgets/installer.py:50 +msgid "" +"This program works with noticeable glitches, but these glitches do not " +"affect the application's functionality." +msgstr "" + +#: bottles/frontend/widgets/installer.py:51 +msgid "This program works with minor glitches." +msgstr "" + +#: bottles/frontend/widgets/installer.py:52 +msgid "This program works perfectly." +msgstr "" + +#: bottles/frontend/widgets/installer.py:90 +#, python-brace-format +msgid "Review for {0}" +msgstr "" + +#: bottles/frontend/widgets/library.py:176 +#: bottles/frontend/widgets/program.py:194 +#, python-brace-format +msgid "Stopping \"{0}\"…" +msgstr "" + +#: bottles/frontend/widgets/program.py:190 +#, python-brace-format +msgid "Launching \"{0}\" with Steam…" +msgstr "" + +#: bottles/frontend/widgets/program.py:214 +#, python-brace-format +msgid "\"{0}\" hidden" +msgstr "" + +#: bottles/frontend/widgets/program.py:216 +#, python-brace-format +msgid "\"{0}\" showed" +msgstr "" + +#: bottles/frontend/widgets/program.py:242 +#, python-brace-format +msgid "\"{0}\" removed" +msgstr "" + +#: bottles/frontend/widgets/program.py:274 +#, python-brace-format +msgid "\"{0}\" renamed to \"{1}\"" +msgstr "" + +#: bottles/frontend/widgets/program.py:297 +#, python-brace-format +msgid "Desktop Entry created for \"{0}\"" +msgstr "" + +#: bottles/frontend/widgets/program.py:313 +#, python-brace-format +msgid "\"{0}\" added to your library" +msgstr "" + +#: bottles/frontend/widgets/program.py:331 +#, python-brace-format +msgid "\"{0}\" added to your Steam library" +msgstr "" + +#: bottles/frontend/windows/crash.py:33 +msgid "Show report" +msgstr "" + +#: bottles/frontend/windows/crash.py:80 +msgid "" +" This issue was reported 5 times and cannot be sent again.\n" +" Report your feedback in one of the below existing reports." +msgstr "" + +#: bottles/frontend/windows/display.py:102 +msgid "Updating display settings, please wait…" +msgstr "" + +#: bottles/frontend/windows/display.py:114 +msgid "Display settings updated" +msgstr "" + +#: bottles/frontend/windows/dlloverrides.py:136 +msgid "No overrides found." +msgstr "" + +#: bottles/frontend/windows/drives.py:71 +msgid "Select Drive Path" +msgstr "" + +#: bottles/frontend/windows/envvars.py:135 +msgid "No environment variables defined." +msgstr "" + +#: bottles/frontend/windows/exclusionpatterns.py:105 +msgid "No exclusion patterns defined." +msgstr "" + +#: bottles/frontend/windows/generic.py:24 +msgid "An error has occurred." +msgstr "აღმოჩენილია შეცდომა." + +#: bottles/frontend/windows/generic.py:91 +#: bottles/frontend/windows/generic.py:137 +#: bottles/frontend/windows/generic.py:182 +msgid "Copy to clipboard" +msgstr "ბუფერში კოპირება" + +#: bottles/frontend/windows/installer.py:62 +msgid "Select Resource File" +msgstr "" + +#: bottles/frontend/windows/installer.py:109 +msgid "Installing Windows dependencies…" +msgstr "" + +#: bottles/frontend/windows/installer.py:110 +msgid "Configuring the bottle…" +msgstr "" + +#: bottles/frontend/windows/installer.py:111 +msgid "Processing installer steps…" +msgstr "" + +#: bottles/frontend/windows/installer.py:112 +msgid "Installing the {}…" +msgstr "" + +#: bottles/frontend/windows/installer.py:113 +msgid "Performing final checks…" +msgstr "" + +#: bottles/frontend/windows/installer.py:117 +#, python-brace-format +msgid "Installing {0}…" +msgstr "" + +#: bottles/frontend/windows/installer.py:119 +#, python-brace-format +msgid "{0} is now available in the programs view." +msgstr "" + +#: bottles/frontend/windows/installer.py:166 +msgid "Installer failed with unknown error" +msgstr "" + +#: bottles/frontend/windows/launchoptions.py:55 +#, python-brace-format +msgid "{0} is already disabled for this bottle." +msgstr "" + +#: bottles/frontend/windows/launchoptions.py:56 +msgid "This setting is different from the bottle's default." +msgstr "" + +#: bottles/frontend/windows/launchoptions.py:214 +msgid "Select Script" +msgstr "" + +#: bottles/frontend/windows/main_window.py:220 +msgid "Custom Bottles Path not Found" +msgstr "" + +#: bottles/frontend/windows/main_window.py:221 +msgid "" +"Falling back to default path. No bottles from the given path will be listed." +msgstr "" + +#: data/com.usebottles.bottles.desktop.in.in:3 +msgid "@APP_NAME@" +msgstr "@APP_NAME@" + +#: data/com.usebottles.bottles.desktop.in.in:4 +#: data/com.usebottles.bottles.metainfo.xml.in:8 +msgid "Run Windows Software" +msgstr "" + +#: data/com.usebottles.bottles.desktop.in.in:13 +msgid "wine;windows;" +msgstr "wine;windows;" + +#: data/com.usebottles.bottles.gschema.xml:6 +msgid "Flatpak migration" +msgstr "" + +#: data/com.usebottles.bottles.gschema.xml:7 +msgid "Toggle the Flatpak migration dialog." +msgstr "" + +#: data/com.usebottles.bottles.gschema.xml:11 +msgid "Dark theme" +msgstr "ბნელი თემა" + +#: data/com.usebottles.bottles.gschema.xml:12 +msgid "Force the use of dark theme." +msgstr "" + +#: data/com.usebottles.bottles.gschema.xml:16 +msgid "Force Offline" +msgstr "" + +#: data/com.usebottles.bottles.gschema.xml:17 +msgid "" +"\"Force disable any network activity even with available network connection." +"\"" +msgstr "" + +#: data/com.usebottles.bottles.gschema.xml:21 +msgid "Toggle update date in list" +msgstr "" + +#: data/com.usebottles.bottles.gschema.xml:22 +msgid "Toggle the update date in list of bottles." +msgstr "" + +#: data/com.usebottles.bottles.gschema.xml:26 +msgid "Steam apps listing" +msgstr "" + +#: data/com.usebottles.bottles.gschema.xml:27 +msgid "Toggle steam apps listing." +msgstr "" + +#: data/com.usebottles.bottles.gschema.xml:31 +msgid "Epic Games listing" +msgstr "" + +#: data/com.usebottles.bottles.gschema.xml:32 +msgid "Toggle epic games listing." +msgstr "" + +#: data/com.usebottles.bottles.gschema.xml:36 +msgid "Ubisoft Connect listing" +msgstr "" + +#: data/com.usebottles.bottles.gschema.xml:37 +msgid "Toggle ubisoft connect listing." +msgstr "" + +#: data/com.usebottles.bottles.gschema.xml:41 +msgid "Window width" +msgstr "ფანჯრის სიგანე" + +#: data/com.usebottles.bottles.gschema.xml:42 +msgid "Change the window width." +msgstr "" + +#: data/com.usebottles.bottles.gschema.xml:46 +msgid "Window height" +msgstr "ფანჯრის სიმაღლე" + +#: data/com.usebottles.bottles.gschema.xml:47 +msgid "Change the window height." +msgstr "" + +#: data/com.usebottles.bottles.gschema.xml:52 +msgid "Show notifications." +msgstr "გაფრთხილებების ჩვენება." + +#: data/com.usebottles.bottles.gschema.xml:56 +msgid "Temp cleaning" +msgstr "" + +#: data/com.usebottles.bottles.gschema.xml:57 +msgid "Clean the temp path when booting the system." +msgstr "" + +#: data/com.usebottles.bottles.gschema.xml:61 +msgid "Release Candidate" +msgstr "" + +#: data/com.usebottles.bottles.gschema.xml:62 +msgid "Toggle release candidate for runners." +msgstr "" + +#: data/com.usebottles.bottles.gschema.xml:66 +msgid "Startup view" +msgstr "" + +#: data/com.usebottles.bottles.gschema.xml:67 +msgid "Choose which view the application should be started in." +msgstr "" + +#: data/com.usebottles.bottles.gschema.xml:72 +msgid "" +"Toggle experimental features such as versioning and installers. Release " +"candidate for runners." +msgstr "" + +#: data/com.usebottles.bottles.gschema.xml:76 +msgid "Steam Proton Support" +msgstr "" + +#: data/com.usebottles.bottles.gschema.xml:77 +msgid "Toggle Steam Proton prefixes support." +msgstr "" + +#: data/com.usebottles.bottles.gschema.xml:81 +msgid "Experiments:sandbox" +msgstr "ექსპერიმენტული სენდბოქსი" + +#: data/com.usebottles.bottles.gschema.xml:82 +msgid "Toggle experimental Sandbox per bottle." +msgstr "" + +#: data/com.usebottles.bottles.gschema.xml:86 +msgid "Automatically close Bottles" +msgstr "" + +#: data/com.usebottles.bottles.gschema.xml:87 +msgid "Close Bottles after starting an executable from the file manager." +msgstr "" + +#: data/com.usebottles.bottles.gschema.xml:91 +msgid "Show sandbox warning" +msgstr "" + +#: data/com.usebottles.bottles.gschema.xml:92 +msgid "Toggle sandbox warning." +msgstr "" + +#: data/com.usebottles.bottles.metainfo.xml.in:11 +msgid "" +"Bottles lets you run Windows software on Linux, such as applications and " +"games. It introduces a workflow that helps you organize by categorizing each " +"software to your liking. Bottles provides several tools and integrations to " +"help you manage and optimize your applications." +msgstr "" + +#: data/com.usebottles.bottles.metainfo.xml.in:12 +msgid "Features:" +msgstr "თვისებები:" + +#: data/com.usebottles.bottles.metainfo.xml.in:14 +msgid "Use pre-configured environments as a base" +msgstr "" + +#: data/com.usebottles.bottles.metainfo.xml.in:15 +msgid "Change runners for any bottle" +msgstr "" + +#: data/com.usebottles.bottles.metainfo.xml.in:16 +msgid "Various optimizations and options for gaming" +msgstr "" + +#: data/com.usebottles.bottles.metainfo.xml.in:17 +msgid "Repair in case software or bottle is broken" +msgstr "" + +#: data/com.usebottles.bottles.metainfo.xml.in:18 +msgid "Install various known dependencies" +msgstr "" + +#: data/com.usebottles.bottles.metainfo.xml.in:19 +msgid "Integrated task manager to manage and monitor processes" +msgstr "" + +#: data/com.usebottles.bottles.metainfo.xml.in:20 +msgid "Backup and restore" +msgstr "" + +#: data/com.usebottles.bottles.metainfo.xml.in:69 +msgid "Fix runners and components from not showing when prereleases are off" +msgstr "" + +#: data/com.usebottles.bottles.metainfo.xml.in:70 +msgid "Fix Steam runtime compatibility with Wine runners" +msgstr "" + +#: data/com.usebottles.bottles.metainfo.xml.in:75 +msgid "A few bug fixes" +msgstr "" + +#: data/com.usebottles.bottles.metainfo.xml.in:80 +msgid "Support for the double-DLL VKD3D" +msgstr "" + +#: data/com.usebottles.bottles.metainfo.xml.in:81 +msgid "Updated Flatpak runtime" +msgstr "" + +#: data/com.usebottles.bottles.metainfo.xml.in:82 +msgid "Minor improvement and fixes to the library" +msgstr "" + +#: data/com.usebottles.bottles.metainfo.xml.in:83 +msgid "Fix the Steam link not being correct" +msgstr "" + +#: data/com.usebottles.bottles.metainfo.xml.in:84 +msgid "Download stable component by default" +msgstr "" + +#: data/com.usebottles.bottles.metainfo.xml.in:85 +msgid "Make window remember dimensions" +msgstr "" + +#: data/com.usebottles.bottles.metainfo.xml.in:90 +msgid "Update metadata information" +msgstr "" + +#: data/com.usebottles.bottles.metainfo.xml.in:95 +msgid "Add more update information and correct release notes version" +msgstr "" + +#: data/com.usebottles.bottles.metainfo.xml.in:100 +msgid "Fixed \"Add to Steam\" button" +msgstr "" + +#: data/com.usebottles.bottles.metainfo.xml.in:101 +msgid "Fixed BottleConfig being not serializable" +msgstr "" + +#: data/com.usebottles.bottles.metainfo.xml.in:102 +msgid "Fixed Patool double extraction failing" +msgstr "" + +#: data/com.usebottles.bottles.metainfo.xml.in:107 +msgid "Correct version" +msgstr "" + +#: data/com.usebottles.bottles.metainfo.xml.in:112 +msgid "Fix crash when creating a bottle" +msgstr "" + +#: data/com.usebottles.bottles.metainfo.xml.in:117 +msgid "Major change: Redesign New Bottle interface" +msgstr "" + +#: data/com.usebottles.bottles.metainfo.xml.in:118 +msgid "Quality of life improvements:" +msgstr "" + +#: data/com.usebottles.bottles.metainfo.xml.in:120 +msgid "Replace emote-love icon with a library in library page" +msgstr "" + +#: data/com.usebottles.bottles.metainfo.xml.in:121 +msgid "Add toast for \"Run Executable\"" +msgstr "" + +#: data/com.usebottles.bottles.metainfo.xml.in:123 +msgid "Bug fixes:" +msgstr "" + +#: data/com.usebottles.bottles.metainfo.xml.in:125 +msgid "Adding a shortcut to Steam resulted in an error" +msgstr "" + +#: data/com.usebottles.bottles.metainfo.xml.in:126 +msgid "Importing backups resulted an error" +msgstr "" + +#: data/com.usebottles.bottles.metainfo.xml.in:127 +msgid "Steam Runtime automatically enabled when using wine-ge-custom" +msgstr "" + +#: data/com.usebottles.bottles.metainfo.xml.in:128 +msgid "" +"Various library-related fixes, like empty covers, and crashes related to " +"missing entries" +msgstr "" + +#: data/com.usebottles.bottles.metainfo.xml.in:129 +msgid "Fix various issues related to text encoding" +msgstr "" + +#: data/com.usebottles.bottles.metainfo.xml.in:136 +msgid "Fix error when downloading if Bottles isn't run from terminal" +msgstr "" + +#: data/com.usebottles.bottles.metainfo.xml.in:143 +msgid "Correct version date" +msgstr "" + +#: data/com.usebottles.bottles.metainfo.xml.in:144 +msgid "Hide NVIDIA-related critical errors on non-NVIDIA systems" +msgstr "" + +#: data/com.usebottles.bottles.metainfo.xml.in:151 +msgid "Gamescope improvements and fixes" +msgstr "" + +#: data/com.usebottles.bottles.metainfo.xml.in:152 +msgid "Dependency installation is faster and more stable" +msgstr "" + +#: data/com.usebottles.bottles.metainfo.xml.in:153 +msgid "The health check has more information for faster debugging" +msgstr "" + +#: data/com.usebottles.bottles.metainfo.xml.in:154 +msgid "NVAPI has a lot of fixes and is more stable, should now work properly" +msgstr "" + +#: data/com.usebottles.bottles.metainfo.xml.in:155 +msgid "Fix crash when downloading a component" +msgstr "" + +#: data/com.usebottles.bottles.metainfo.xml.in:156 +msgid "Backend code improvement by avoiding spin-lock" +msgstr "" + +#: data/com.usebottles.bottles.metainfo.xml.in:157 +msgid "More variables for installer scripting" +msgstr "" + +#: data/com.usebottles.bottles.metainfo.xml.in:158 +msgid "Fix onboard dialog showing \"All ready\" while it was not ready" +msgstr "" + +#: data/com.usebottles.bottles.metainfo.xml.in:159 +msgid "Improvement to build system" +msgstr "" + +#: data/com.usebottles.bottles.metainfo.xml.in:160 +msgid "Enabling VKD3D by default when creating bottles for gaming" +msgstr "" + +#: data/com.usebottles.bottles.metainfo.xml.in:161 +msgid "Fix crashes when reading Steam files with bad encodings" +msgstr "" + +#: data/com.usebottles.bottles.metainfo.xml.in:162 +msgid "" +"Fix components not updated correctly in the UI after installation/" +"uninstallation" +msgstr "" + +#: data/com.usebottles.bottles.metainfo.xml.in:163 +msgid "More FSR fixes" +msgstr "" + +#: data/com.usebottles.bottles.metainfo.xml.in:164 +msgid "" +"Fix the issue when a program closes after it was launched from \"Run " +"executable\"" +msgstr "" + +#: data/com.usebottles.bottles.metainfo.xml.in:165 +msgid "and many, many, many more!" +msgstr "" diff --git a/po/lt.po b/po/lt.po index 17679293e73..00a21d0007b 100644 --- a/po/lt.po +++ b/po/lt.po @@ -8,8 +8,8 @@ msgstr "" "Project-Id-Version: bottles\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2023-03-27 13:50+0530\n" -"PO-Revision-Date: 2022-06-20 16:30+0000\n" -"Last-Translator: Tillo \n" +"PO-Revision-Date: 2024-10-27 02:15+0000\n" +"Last-Translator: arnas \n" "Language-Team: Lithuanian \n" "Language: lt\n" @@ -19,7 +19,7 @@ msgstr "" "Plural-Forms: nplurals=3; plural=(n % 10 == 1 && (n % 100 < 11 || n % 100 > " "19)) ? 0 : ((n % 10 >= 2 && n % 10 <= 9 && (n % 100 < 11 || n % 100 > 19)) ? " "1 : 2);\n" -"X-Generator: Weblate 4.13.1-dev\n" +"X-Generator: Weblate 5.8.2-dev\n" #: bottles/backend/managers/backup.py:48 bottles/backend/managers/backup.py:95 msgid "No path specified" @@ -28,7 +28,7 @@ msgstr "" #: bottles/backend/managers/backup.py:56 #, python-brace-format msgid "Backup {0}" -msgstr "" +msgstr "Atsarginė kopija {0}" #: bottles/backend/managers/backup.py:101 #, python-brace-format @@ -37,11 +37,11 @@ msgstr "" #: bottles/backend/managers/manager.py:1057 msgid "Fail to install components, tried 3 times." -msgstr "" +msgstr "Nepavyko įdiegti komponentų, bandyta 3 kartus." #: bottles/backend/managers/manager.py:1068 msgid "Missing essential components. Installing…" -msgstr "" +msgstr "Trūksta reikalingų komponentų. Diegiama…" #: bottles/backend/managers/manager.py:1145 msgid "Failed to create bottle directory." @@ -53,11 +53,11 @@ msgstr "" #: bottles/backend/managers/manager.py:1162 msgid "Generating bottle configuration…" -msgstr "" +msgstr "Generuojama „bottle“ konfigūracija…" #: bottles/backend/managers/manager.py:1185 msgid "Template found, applying…" -msgstr "" +msgstr "Rastas šablonas, pritaikoma…" #. execute wineboot on the bottle path #: bottles/backend/managers/manager.py:1197 @@ -66,7 +66,7 @@ msgstr "" #: bottles/backend/managers/manager.py:1199 msgid "Wine config updated!" -msgstr "" +msgstr "Wine konfigūracija atnaujinta!" #: bottles/backend/managers/manager.py:1207 msgid "Running as Flatpak, sandboxing userdir…" @@ -78,45 +78,45 @@ msgstr "" #: bottles/backend/managers/manager.py:1250 msgid "Setting Windows version…" -msgstr "" +msgstr "Nustatoma Windows versija…" #: bottles/backend/managers/manager.py:1260 msgid "Apply CMD default settings…" -msgstr "" +msgstr "Pritaikomi numatytieji CMD nustatymai…" #: bottles/backend/managers/manager.py:1268 msgid "Optimizing environment…" -msgstr "" +msgstr "Vykdoma aplinkos optimizacija…" #: bottles/backend/managers/manager.py:1279 #, python-brace-format msgid "Applying environment: {0}…" -msgstr "" +msgstr "Pritaikoma aplinka: {0}…" #: bottles/backend/managers/manager.py:1289 msgid "(!) Using a custom environment recipe…" -msgstr "" +msgstr "(!) Naudojamas pritaikytos aplinkos receptas…" #: bottles/backend/managers/manager.py:1292 msgid "(!) Recipe not not found or not valid…" -msgstr "" +msgstr "(!) Receptas nerastas arba klaidingas…" #: bottles/backend/managers/manager.py:1309 msgid "Installing DXVK…" -msgstr "" +msgstr "Diegiama DXVK…" #: bottles/backend/managers/manager.py:1317 msgid "Installing VKD3D…" -msgstr "" +msgstr "Diegiama VKD3D…" #: bottles/backend/managers/manager.py:1326 msgid "Installing DXVK-NVAPI…" -msgstr "" +msgstr "Diegiama DXVK-NVAPI…" #: bottles/backend/managers/manager.py:1335 #, python-format msgid "Installing dependency: %s …" -msgstr "" +msgstr "Diegiama priklausomybė: %s …" #: bottles/backend/managers/manager.py:1345 msgid "Creating versioning state 0…" @@ -124,11 +124,11 @@ msgstr "" #: bottles/backend/managers/manager.py:1353 msgid "Finalizing…" -msgstr "" +msgstr "Užbaigiama…" #: bottles/backend/managers/manager.py:1364 msgid "Caching template…" -msgstr "" +msgstr "Išsaugomas šablonas…" #: bottles/backend/managers/versioning.py:83 msgid "Committing state …" @@ -141,24 +141,24 @@ msgstr "" #: bottles/backend/managers/versioning.py:96 #, python-brace-format msgid "New state [{0}] created successfully!" -msgstr "" +msgstr "Nauja būsena [{0}] sėkmingai sukurta!" #: bottles/backend/managers/versioning.py:123 msgid "States list retrieved successfully!" -msgstr "" +msgstr "Sėkmingai gautas būsenų sąrašas!" #: bottles/backend/managers/versioning.py:153 #, python-brace-format msgid "State {0} restored successfully!" -msgstr "" +msgstr "Būsena {0} sėkmingai atkurta!" #: bottles/backend/managers/versioning.py:155 msgid "Restoring state {} …" -msgstr "" +msgstr "Atkuriama būsena {} …" #: bottles/backend/managers/versioning.py:162 msgid "State not found" -msgstr "" +msgstr "Būsena nerasta" #: bottles/backend/managers/versioning.py:168 msgid "State {} is already the active state" @@ -166,7 +166,7 @@ msgstr "" #: bottles/frontend/main.py:112 msgid "Show version" -msgstr "" +msgstr "Rodyti versiją" #: bottles/frontend/main.py:120 msgid "Executable path" @@ -174,28 +174,28 @@ msgstr "" #: bottles/frontend/main.py:128 msgid "lnk path" -msgstr "" +msgstr "lnk path" #: bottles/frontend/main.py:136 bottles/frontend/ui/library-entry.blp:118 #: bottles/frontend/ui/list-entry.blp:5 msgid "Bottle name" -msgstr "" +msgstr "„Bottle“ pavadinimas" #: bottles/frontend/main.py:144 msgid "Pass arguments" -msgstr "" +msgstr "Siųsti argumentus" #: bottles/frontend/main.py:203 msgid "Invalid URI (syntax: bottles:run//)" -msgstr "" +msgstr "Klaidingas URI (syntax: bottles:run//)" #: bottles/frontend/main.py:244 msgid "[Quit] request received." -msgstr "" +msgstr "[Quit] Prašymas gautas." #: bottles/frontend/main.py:253 msgid "[Help] request received." -msgstr "" +msgstr "[Help] Prašymas gautas." #: bottles/frontend/main.py:261 msgid "[Refresh] request received." @@ -203,25 +203,25 @@ msgstr "" #: bottles/frontend/main.py:294 msgid "Donate" -msgstr "" +msgstr "Aukoti" #: bottles/frontend/main.py:299 msgid "Third-Party Libraries and Special Thanks" -msgstr "" +msgstr "Trečiųjų šalių bibliotekos bei ypatingas Ačiū" #: bottles/frontend/main.py:325 msgid "Sponsored and Funded by" -msgstr "" +msgstr "Remia ir finansuoja" # Translators: Bottles is a proper noun referring to the app #: bottles/frontend/ui/about.blp:5 msgid "Copyright © 2017 Bottles Developers" -msgstr "" +msgstr "Saugomos autorinės teisės © 2017 Bottles kūrėjai" # Translators: Bottles is a proper noun referring to the app #: bottles/frontend/ui/about.blp:10 msgid "Bottles Developers" -msgstr "" +msgstr "„Bottles“ kūrėjai" #: bottles/frontend/ui/about.blp:12 msgid "translator_credits" @@ -229,17 +229,17 @@ msgstr "" #: bottles/frontend/ui/component-entry.blp:4 msgid "Component version" -msgstr "" +msgstr "Komponento versija" #: bottles/frontend/ui/component-entry.blp:12 #: bottles/frontend/ui/dependency-entry.blp:29 #: bottles/frontend/ui/program-entry.blp:77 msgid "Uninstall" -msgstr "" +msgstr "Išinstaliuoti" #: bottles/frontend/ui/component-entry.blp:23 msgid "Browse Files" -msgstr "" +msgstr "Naršyti failus" #: bottles/frontend/ui/component-entry.blp:34 msgid "" @@ -282,7 +282,7 @@ msgstr "" #: bottles/frontend/ui/dependency-entry.blp:51 msgid "Category" -msgstr "" +msgstr "Kategorija" #: bottles/frontend/ui/dependency-entry.blp:64 msgid "Download & Install this Dependency" @@ -293,6 +293,8 @@ msgid "" "An installation error occurred. Restart Bottles to read the Crash Report or " "run it via terminal to read the output." msgstr "" +"Iškilo diegimo klaida. Perkraukite „Bottles“ jei norite skaityti klaidos " +"ataskaitą, arba paleiskite per terminalą norint matyti išvestį." #: bottles/frontend/ui/dependency-entry.blp:93 msgid "Dependency Menu" @@ -304,7 +306,7 @@ msgstr "" #: bottles/frontend/ui/details-bottle.blp:24 msgid "Browse Files…" -msgstr "" +msgstr "Naršyti failus…" #: bottles/frontend/ui/details-bottle.blp:28 msgid "Duplicate Bottle…" @@ -328,20 +330,20 @@ msgstr "" #: bottles/frontend/ui/details-bottle.blp:38 msgid "Export Configuration…" -msgstr "" +msgstr "Eksportuoti konfigūraciją…" #: bottles/frontend/ui/details-bottle.blp:45 #: bottles/frontend/views/bottle_details.py:344 msgid "Show Hidden Programs" -msgstr "" +msgstr "Rodyti paslėptas programas" #: bottles/frontend/ui/details-bottle.blp:49 msgid "Search for new programs" -msgstr "" +msgstr "Ieškoti naujų programų" #: bottles/frontend/ui/details-bottle.blp:56 msgid "Delete Bottle…" -msgstr "" +msgstr "Ištrinti Bottle…" #: bottles/frontend/ui/details-bottle.blp:73 #: bottles/frontend/ui/details-dependencies.blp:99 @@ -351,32 +353,32 @@ msgstr "" #: bottles/frontend/ui/details-bottle.blp:90 msgid "Force Stop all Processes" -msgstr "" +msgstr "Priverstinai sustabdyti visus procesus" #: bottles/frontend/ui/details-bottle.blp:94 msgid "Simulate a Windows system shutdown." -msgstr "" +msgstr "Windows sistemos išjungimo simuliacija." #: bottles/frontend/ui/details-bottle.blp:95 msgid "Shutdown" -msgstr "" +msgstr "Išjungti" #: bottles/frontend/ui/details-bottle.blp:99 msgid "Simulate a Windows system reboot." -msgstr "" +msgstr "Windows sistemos perkrovimo simuliacija." #: bottles/frontend/ui/details-bottle.blp:100 msgid "Reboot" -msgstr "" +msgstr "Perkrauti" #: bottles/frontend/ui/details-bottle.blp:118 #: bottles/frontend/ui/dialog-launch-options.blp:6 msgid "Launch Options" -msgstr "" +msgstr "Paleidimo nustatymai" #: bottles/frontend/ui/details-bottle.blp:135 msgid "Run in Terminal" -msgstr "" +msgstr "Paleisti terminale" #: bottles/frontend/ui/details-bottle.blp:148 msgid "Drop files to execute them" @@ -384,16 +386,16 @@ msgstr "" #: bottles/frontend/ui/details-bottle.blp:164 msgid "My bottle" -msgstr "" +msgstr "Mano bottle" #: bottles/frontend/ui/details-bottle.blp:177 msgid "Win64" -msgstr "" +msgstr "Win64" #: bottles/frontend/ui/details-bottle.blp:189 #: bottles/frontend/ui/list-entry.blp:12 bottles/frontend/ui/new.blp:71 msgid "Environment" -msgstr "" +msgstr "Aplinka" #: bottles/frontend/ui/details-bottle.blp:201 #: bottles/frontend/ui/details-preferences.blp:14 @@ -404,16 +406,16 @@ msgstr "" #: bottles/frontend/ui/details-bottle.blp:213 #: bottles/frontend/ui/list-entry.blp:21 msgid "Versioning enabled for this bottle" -msgstr "" +msgstr "Įjungta versijos kontrolė šiam bottle" #: bottles/frontend/ui/details-bottle.blp:218 msgid "Versioning is active for this bottle." -msgstr "" +msgstr "Šio bottle versijos kontrolė yra aktyvi." #: bottles/frontend/ui/details-bottle.blp:227 #: bottles/frontend/ui/list-entry.blp:31 msgid "0" -msgstr "" +msgstr "0" #: bottles/frontend/ui/details-bottle.blp:247 msgid "Run Executable…" @@ -421,7 +423,7 @@ msgstr "" #: bottles/frontend/ui/details-bottle.blp:272 msgid "Programs" -msgstr "" +msgstr "Programos" #: bottles/frontend/ui/details-bottle.blp:275 msgid "" @@ -955,9 +957,8 @@ msgid "Operations" msgstr "" #: bottles/frontend/ui/dialog-bottle-picker.blp:4 -#, fuzzy msgid "Select Bottle" -msgstr "Bottles" +msgstr "Pasirinkti Bottle" #: bottles/frontend/ui/dialog-bottle-picker.blp:16 #: bottles/frontend/ui/dialog-proton-alert.blp:16 @@ -1945,7 +1946,7 @@ msgstr "" #: bottles/frontend/ui/preferences.blp:42 #: data/com.usebottles.bottles.gschema.xml:46 msgid "Notifications" -msgstr "" +msgstr "Pranešimai" #: bottles/frontend/ui/preferences.blp:43 msgid "Show notifications for downloads and installs." @@ -2058,7 +2059,7 @@ msgstr "" #: bottles/frontend/ui/preferences.blp:297 #: data/com.usebottles.bottles.gschema.xml:66 msgid "Experiments" -msgstr "" +msgstr "Eksperimentai" #: bottles/frontend/ui/preferences.blp:300 msgid "" @@ -2177,9 +2178,8 @@ msgstr "" #: bottles/frontend/views/bottle_details.py:270 #: bottles/frontend/views/bottle_details.py:398 #: bottles/frontend/views/list.py:128 -#, fuzzy msgid "Select Executable" -msgstr "Bottles" +msgstr "Pasirinkti Executable" #: bottles/frontend/views/bottle_details.py:273 msgid "Add" @@ -2412,9 +2412,8 @@ msgid "Select Bottles Path" msgstr "Bottles" #: bottles/frontend/views/preferences.py:198 -#, fuzzy msgid "Relaunch Bottles?" -msgstr "Bottles" +msgstr "Perkrauti Bottles?" #: bottles/frontend/views/preferences.py:199 msgid "" @@ -2603,9 +2602,8 @@ msgid "Copy to clipboard" msgstr "" #: bottles/frontend/windows/installer.py:62 -#, fuzzy msgid "Select Resource File" -msgstr "Bottles" +msgstr "Pasirinkite išteklių failą" #: bottles/frontend/windows/installer.py:109 msgid "Installing Windows dependencies…" @@ -2639,7 +2637,7 @@ msgstr "" #: bottles/frontend/windows/installer.py:166 msgid "Installer failed with unknown error" -msgstr "" +msgstr "Įvyko diegimo klaida dėl nežinomos priežasties" #: bottles/frontend/windows/launchoptions.py:56 #, python-brace-format @@ -2651,9 +2649,8 @@ msgid "This setting is different from the bottle's default." msgstr "" #: bottles/frontend/windows/launchoptions.py:215 -#, fuzzy msgid "Select Script" -msgstr "Bottles" +msgstr "Pasirinkite Script" #: bottles/frontend/windows/main_window.py:220 msgid "Custom Bottles Path not Found" @@ -2670,7 +2667,6 @@ msgstr "" #: data/com.usebottles.bottles.desktop.in.in:4 #: data/com.usebottles.bottles.metainfo.xml.in:8 -#, fuzzy msgid "Run Windows Software" msgstr "Paleisti Windows programas" @@ -2688,11 +2684,11 @@ msgstr "" #: data/com.usebottles.bottles.gschema.xml:11 msgid "Dark theme" -msgstr "" +msgstr "Tamsus rėžimas" #: data/com.usebottles.bottles.gschema.xml:12 msgid "Force the use of dark theme." -msgstr "" +msgstr "Priverstinai naudoti tamsųjį rėžimą." #: data/com.usebottles.bottles.gschema.xml:16 msgid "Toggle update date in list" @@ -2744,7 +2740,7 @@ msgstr "" #: data/com.usebottles.bottles.gschema.xml:47 msgid "Show notifications." -msgstr "" +msgstr "Rodyti pranešimus." #: data/com.usebottles.bottles.gschema.xml:51 msgid "Temp cleaning" @@ -2756,7 +2752,7 @@ msgstr "" #: data/com.usebottles.bottles.gschema.xml:56 msgid "Release Candidate" -msgstr "" +msgstr "Paleisti kandidatą" #: data/com.usebottles.bottles.gschema.xml:57 msgid "Toggle release candidate for runners." @@ -2764,11 +2760,11 @@ msgstr "" #: data/com.usebottles.bottles.gschema.xml:61 msgid "Startup view" -msgstr "" +msgstr "Paleidimo vaizdas" #: data/com.usebottles.bottles.gschema.xml:62 msgid "Choose which view the application should be started in." -msgstr "" +msgstr "Pasirinkti kurį vaizdą matysite pradėjus aplikaciją." #: data/com.usebottles.bottles.gschema.xml:67 msgid "" @@ -2794,7 +2790,7 @@ msgstr "" #: data/com.usebottles.bottles.gschema.xml:81 msgid "Automatically close Bottles" -msgstr "" +msgstr "Automatiškai išjungti Bottles" #: data/com.usebottles.bottles.gschema.xml:82 msgid "Close Bottles after starting an executable from the file manager." diff --git a/po/pl.po b/po/pl.po index 72c4927bdb1..fb49f87b633 100644 --- a/po/pl.po +++ b/po/pl.po @@ -8,17 +8,17 @@ msgstr "" "Project-Id-Version: bottles\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2023-03-27 13:50+0530\n" -"PO-Revision-Date: 2024-09-23 17:15+0000\n" -"Last-Translator: Piotr Wieczorek \n" +"PO-Revision-Date: 2025-01-15 18:20+0000\n" +"Last-Translator: PC \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 " -"|| n%100>=20) ? 1 : 2;\n" -"X-Generator: Weblate 5.8-dev\n" +"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 " +"|| n%100>=20) ? 1 : 2);\n" +"X-Generator: Weblate 5.10-dev\n" #: bottles/backend/managers/backup.py:48 bottles/backend/managers/backup.py:95 msgid "No path specified" @@ -1946,9 +1946,8 @@ msgid "_Gaming" msgstr "_Granie" #: bottles/frontend/ui/new.blp:101 -#, fuzzy msgid "C_ustom" -msgstr "Niestandardowe" +msgstr "własne" #: bottles/frontend/ui/new.blp:114 msgid "Custom" @@ -2580,11 +2579,11 @@ msgid "" "Bottles, as not doing so can cause data loss, corruption and programs to " "malfunction." msgstr "" -"Ten program będzie musiał zostać ponownie uruchomiony, aby użyć tego folderu." +"Butelka będzie musiała zostać uruchomiona ponownie aby użyć tego folderu.\n" "\n" -"Upewnij się, że zamknąłeś każdy program uruchomiony w tym programie, zanim " -"ponownie go uruchomisz. Nie zrobienie tego może spowodować utratę/" -"uszkodzenie danych i doprowadzić programy do niepoprawnego działania." +"Upewnij się, że zamknąłeś każdy program uruchomiony w Butelce, zanim " +"ponownie ją uruchomisz. Nie zrobienie tego może spowodować utratę i " +"uszkodzenie danych oraz doprowadzić programy do niepoprawnego działania." #: bottles/frontend/views/preferences.py:202 msgid "_Relaunch" @@ -3137,7 +3136,7 @@ msgstr "Ulepszenia \"Quality of life\":" #: data/com.usebottles.bottles.metainfo.xml.in:114 msgid "Replace emote-love icon with library in library page" -msgstr "" +msgstr "zastąpi ikonę emote-love biblioteką na stronie biblioteki" #: data/com.usebottles.bottles.metainfo.xml.in:115 msgid "Add toast for \"Run Executable\"" @@ -3149,11 +3148,11 @@ msgstr "Poprawki błędów:" #: data/com.usebottles.bottles.metainfo.xml.in:119 msgid "Adding shortcut to Steam resulted an error" -msgstr "" +msgstr "Dodawanie skrótu do Steam zakończyło się nie powodzeniem" #: data/com.usebottles.bottles.metainfo.xml.in:120 msgid "Importing backups resulted an error" -msgstr "Wystąpił błąd podczas importownia kopii zapasowej" +msgstr "Wystąpił błąd podczas importowania kopii zapasowej" #: data/com.usebottles.bottles.metainfo.xml.in:121 msgid "Steam Runtime automatically enabled when using wine-ge-custom" @@ -3165,6 +3164,8 @@ msgid "" "Various library related fixes, like empty covers, and crashes related to " "missing entries" msgstr "" +"Różne poprawki związane z biblioteką, takie jak puste okładki i awarie " +"związane z brakującymi wpisami" #: data/com.usebottles.bottles.metainfo.xml.in:123 msgid "Fix various issues related to text encoding" @@ -3173,16 +3174,16 @@ msgstr "Naprawiono różnorodne problemy z dekodowaniem tekstu" #: data/com.usebottles.bottles.metainfo.xml.in:130 msgid "Fix error when downloading if Bottles isn't run from terminal" msgstr "" -"Naprawiono błąd przy pobieraniu, kiedy ten program nie został uruchomiony z " -"terminala" +"Naprawiono błąd przy pobieraniu, kiedy program bottles nie został " +"uruchomiony z terminala" #: data/com.usebottles.bottles.metainfo.xml.in:137 msgid "Correct version date" -msgstr "Poprawiono datę wydania wesji" +msgstr "Poprawiono datę wydania wersji" #: data/com.usebottles.bottles.metainfo.xml.in:138 msgid "Hide NVIDIA-related critical errors on non NVIDIA systems" -msgstr "" +msgstr "Ukryj krytyczne błędy związane z NVIDIA na systemach innych niż NVIDIA" #: data/com.usebottles.bottles.metainfo.xml.in:145 msgid "Gamescope improvements and fixes" @@ -3195,6 +3196,8 @@ msgstr "Instalacja wymaganych składników jest szybsza i bardziej stabilna" #: data/com.usebottles.bottles.metainfo.xml.in:147 msgid "The health check has more information for faster debugging" msgstr "" +"Kontrola stanu zdrowia zawiera więcej informacji, co umożliwia szybsze " +"debugowanie" #: data/com.usebottles.bottles.metainfo.xml.in:148 msgid "NVAPI has a lot of fixes and is more stable, should now work properly" @@ -3208,7 +3211,7 @@ msgstr "Naprawiono zawieszanie programu przy pobieraniu komponentów" #: data/com.usebottles.bottles.metainfo.xml.in:150 msgid "Backend code improvement by avoiding spin-lock" -msgstr "" +msgstr "Ulepszenie kodu zaplecza poprzez unikanie spin-lock" #: data/com.usebottles.bottles.metainfo.xml.in:151 msgid "More variables for installer scripting" @@ -3217,38 +3220,46 @@ msgstr "Więcej zmiennych w skrypcie instalatora" #: data/com.usebottles.bottles.metainfo.xml.in:152 msgid "Fix onboard dialog showing \"All ready\" while it was in fact not ready" msgstr "" +"Naprawiono pokładowy dialog pokazujący „Wszystko gotowe”, gdy w " +"rzeczywistości nie było gotowe" #: data/com.usebottles.bottles.metainfo.xml.in:153 msgid "Improvement to build system" -msgstr "" +msgstr "Ulepszenie systemu kompilacji" #: data/com.usebottles.bottles.metainfo.xml.in:154 msgid "Enabling VKD3D by default when creating bottles for gaming" -msgstr "" +msgstr "Domyślne włączanie VKD3D podczas tworzenia butelek do gier" #: data/com.usebottles.bottles.metainfo.xml.in:155 msgid "Fix crashes when reading Steam files with bad encodings" msgstr "" +"Naprawiono awarie występujące podczas odczytu plików Steam z nieprawidłowym " +"kodowaniem" #: data/com.usebottles.bottles.metainfo.xml.in:156 msgid "" "Fix components not updated correctly in the UI after installation/" "uninstallation" msgstr "" +"Naprawa komponentów, które nie zostały poprawnie zaktualizowane w " +"interfejsie użytkownika po instalacji/odinstalowaniu" #: data/com.usebottles.bottles.metainfo.xml.in:157 msgid "More FSR fixes" -msgstr "" +msgstr "więcej napraw FSR" #: data/com.usebottles.bottles.metainfo.xml.in:158 msgid "" "Fix the issue when a program closes after it was launched from \"Run " "executable\"" msgstr "" +"napraw problem gdy program ulegnie awarii po tym jak został uruchomiony z " +"\"wykonaj program\"" #: data/com.usebottles.bottles.metainfo.xml.in:159 msgid "and many, many, many more!" -msgstr "" +msgstr "i wiele, wiele, wiele więcej!" #~ msgid "Calculating…" #~ msgstr "Obliczanie…" diff --git a/po/pt.po b/po/pt.po index 92a838e89e0..839b8877630 100644 --- a/po/pt.po +++ b/po/pt.po @@ -8,8 +8,8 @@ msgstr "" "Project-Id-Version: bottles\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2023-03-27 13:50+0530\n" -"PO-Revision-Date: 2024-09-29 12:15+0000\n" -"Last-Translator: Marcos \n" +"PO-Revision-Date: 2024-12-30 04:00+0000\n" +"Last-Translator: Diego Siqueira \n" "Language-Team: Portuguese \n" "Language: pt\n" @@ -17,12 +17,11 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n > 1;\n" -"X-Generator: Weblate 5.8-dev\n" +"X-Generator: Weblate 5.10-dev\n" #: bottles/backend/managers/backup.py:48 bottles/backend/managers/backup.py:95 -#, fuzzy msgid "No path specified" -msgstr "Caminho não especificado" +msgstr "Nenhum caminho especificado" #: bottles/backend/managers/backup.py:56 #, python-brace-format @@ -1930,7 +1929,6 @@ msgid "C_reate" msgstr "C_riar" #: bottles/frontend/ui/new.blp:53 -#, fuzzy msgid "Bottle Name" msgstr "Nome do Bottle" @@ -2576,21 +2574,23 @@ msgstr "_Reiniciar" #: bottles/frontend/views/preferences.py:243 msgid "Based on Valve's Wine, includes staging and Proton patches." -msgstr "" +msgstr "Baseado no Valve's Wine, inclui testes e patches Proton." #: bottles/frontend/views/preferences.py:244 msgid "Based on Wine upstream, includes staging and Proton patches." -msgstr "" +msgstr "Baseado no Wine upstream, inclui testes e patches Proton." #: bottles/frontend/views/preferences.py:247 msgid "Based on Wine upstream, includes staging patches." -msgstr "" +msgstr "Baseado no Wine upstream, inclui testes e patches de teste." #: bottles/frontend/views/preferences.py:248 msgid "" "Based on Valve's Wine, includes staging, Proton and Steam-specific patches. " "Requires the Steam Runtime turned on." msgstr "" +"Baseado no Valve's Wine, inclui patches específicos de teste, Proton e " +"Steam. Requer que o Steam Runtime esteja ativado." #: bottles/frontend/views/preferences.py:250 msgid "Other" @@ -3112,7 +3112,7 @@ msgstr "Melhorias na qualidade de vida:" #: data/com.usebottles.bottles.metainfo.xml.in:114 msgid "Replace emote-love icon with library in library page" -msgstr "" +msgstr "Substitua o ícone emote-love pela biblioteca na página da biblioteca" #: data/com.usebottles.bottles.metainfo.xml.in:115 msgid "Add toast for \"Run Executable\"" @@ -3124,7 +3124,7 @@ msgstr "Correções de bugs:" #: data/com.usebottles.bottles.metainfo.xml.in:119 msgid "Adding shortcut to Steam resulted an error" -msgstr "" +msgstr "Adicionar atalho ao Steam resultou em erro" #: data/com.usebottles.bottles.metainfo.xml.in:120 msgid "Importing backups resulted an error" @@ -3141,6 +3141,8 @@ msgid "" "Various library related fixes, like empty covers, and crashes related to " "missing entries" msgstr "" +"Várias correções relacionadas à biblioteca, como capas vazias e falhas " +"relacionadas a entradas ausentes" #: data/com.usebottles.bottles.metainfo.xml.in:123 msgid "Fix various issues related to text encoding" @@ -3158,6 +3160,8 @@ msgstr "Data correta da versão" #: data/com.usebottles.bottles.metainfo.xml.in:138 msgid "Hide NVIDIA-related critical errors on non NVIDIA systems" msgstr "" +"Ocultar erros críticos relacionados à NVIDIA em sistemas que não sejam da " +"NVIDIA" #: data/com.usebottles.bottles.metainfo.xml.in:145 msgid "Gamescope improvements and fixes" @@ -3194,6 +3198,8 @@ msgstr "Mais variáveis para o script do instalador" #: data/com.usebottles.bottles.metainfo.xml.in:152 msgid "Fix onboard dialog showing \"All ready\" while it was in fact not ready" msgstr "" +"Correção da caixa de diálogo integrada mostrando \"Tudo pronto\" quando na " +"verdade não estava pronto" #: data/com.usebottles.bottles.metainfo.xml.in:153 msgid "Improvement to build system" diff --git a/po/pt_BR.po b/po/pt_BR.po index fd9294ef1d8..72dacd0fcd5 100644 --- a/po/pt_BR.po +++ b/po/pt_BR.po @@ -8,8 +8,8 @@ msgstr "" "Project-Id-Version: bottles\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2023-03-27 13:50+0530\n" -"PO-Revision-Date: 2024-07-05 18:41+0000\n" -"Last-Translator: Kauã Azevedo da Silva Vicente \n" +"PO-Revision-Date: 2025-01-15 18:20+0000\n" +"Last-Translator: John Peter Sa \n" "Language-Team: Portuguese (Brazil) \n" "Language: pt_BR\n" @@ -17,7 +17,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n > 1;\n" -"X-Generator: Weblate 5.7-dev\n" +"X-Generator: Weblate 5.10-dev\n" #: bottles/backend/managers/backup.py:48 bottles/backend/managers/backup.py:95 msgid "No path specified" @@ -35,7 +35,7 @@ msgstr "Importando backup: {0}" #: bottles/backend/managers/manager.py:1057 msgid "Fail to install components, tried 3 times." -msgstr "Falha ao instalar componentes, 3 tentativas." +msgstr "Falha ao instalar componentes, 3 tentativas foram feitas." #: bottles/backend/managers/manager.py:1068 msgid "Missing essential components. Installing…" @@ -51,7 +51,7 @@ msgstr "Falha ao criar diretório/arquivo de espaço reservado." #: bottles/backend/managers/manager.py:1162 msgid "Generating bottle configuration…" -msgstr "Gerando o arquivo de configuração da garrafa…" +msgstr "Gerando a configuração da garrafa…" #: bottles/backend/managers/manager.py:1185 msgid "Template found, applying…" @@ -80,16 +80,16 @@ msgstr "Configurando a versão do Windows…" #: bottles/backend/managers/manager.py:1260 msgid "Apply CMD default settings…" -msgstr "Aplicar definições iniciais do CMD…" +msgstr "Aplicar configurações padrões do CMD…" #: bottles/backend/managers/manager.py:1268 msgid "Optimizing environment…" -msgstr "Otimizando o ambiente…" +msgstr "Otimizando ambiente…" #: bottles/backend/managers/manager.py:1279 #, python-brace-format msgid "Applying environment: {0}…" -msgstr "Aplicando o ambiente: {0} …" +msgstr "Aplicando ambiente: {0} …" #: bottles/backend/managers/manager.py:1289 msgid "(!) Using a custom environment recipe…" diff --git a/po/ru.po b/po/ru.po index 17e30599850..dc1bd63ba96 100644 --- a/po/ru.po +++ b/po/ru.po @@ -8,7 +8,7 @@ msgstr "" "Project-Id-Version: bottles\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2023-03-27 13:50+0530\n" -"PO-Revision-Date: 2024-08-15 06:09+0000\n" +"PO-Revision-Date: 2025-01-15 18:20+0000\n" "Last-Translator: Степан Наумов \n" "Language-Team: Russian \n" @@ -16,9 +16,9 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && " -"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" -"X-Generator: Weblate 5.7-dev\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && " +"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" +"X-Generator: Weblate 5.10-dev\n" #: bottles/backend/managers/backup.py:48 bottles/backend/managers/backup.py:95 msgid "No path specified" @@ -2954,7 +2954,7 @@ msgstr "Запускайте программы Windows на Linux с помощ #: data/com.usebottles.bottles.metainfo.xml.in:12 msgid "Bottle software and enjoy at your leisure!" -msgstr "Разливайте ПО по бутылкам и наслаждайтесь на досуге" +msgstr "Разливайте ПО по бутылкам и наслаждайтесь на досуге!" #: data/com.usebottles.bottles.metainfo.xml.in:13 msgid "" @@ -2971,7 +2971,7 @@ msgid "" "Bottle versioning keeps your work safe now and lets you restore it later!" msgstr "" "Система управления версиями бутылок обеспечивает сохранность вашей текущей " -"работы, а при необходимости позволяет её восстановить." +"работы, а при необходимости позволяет её восстановить!" #: data/com.usebottles.bottles.metainfo.xml.in:17 msgid "Features:" diff --git a/po/vi.po b/po/vi.po index 7bb5717b98d..01c4e3c8e7c 100644 --- a/po/vi.po +++ b/po/vi.po @@ -8,8 +8,8 @@ msgstr "" "Project-Id-Version: bottles\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2023-03-27 13:50+0530\n" -"PO-Revision-Date: 2024-04-01 11:01+0000\n" -"Last-Translator: Hữu Quốc Kiệt Nguyễn \n" +"PO-Revision-Date: 2025-01-08 14:04+0000\n" +"Last-Translator: rezarria \n" "Language-Team: Vietnamese \n" "Language: vi\n" @@ -17,7 +17,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -"X-Generator: Weblate 5.5-dev\n" +"X-Generator: Weblate 5.10-dev\n" #: bottles/backend/managers/backup.py:48 bottles/backend/managers/backup.py:95 msgid "No path specified" @@ -545,7 +545,7 @@ msgstr "Tìm kiếm các gói phụ thuộc…" #: bottles/frontend/ui/preferences.blp:178 #: bottles/frontend/ui/preferences.blp:235 msgid "You're offline :(" -msgstr "" +msgstr "Bạn hiện đang offline :(" #: bottles/frontend/ui/details-dependencies.blp:25 msgid "Bottles is running in offline mode, so dependencies are not available." @@ -706,18 +706,16 @@ msgid "FidelityFX Super Resolution" msgstr "" #: bottles/frontend/ui/details-preferences.blp:106 -#, fuzzy msgid "Increase performance at the expense of visuals. Only works on Vulkan." -msgstr "Cải thiện hiệu suất với chi phí sử dụng năng lượng gia tăng." +msgstr "Cải thiện hiệu suất đồ hoạ. Chỉ dành cho Vulkan." #: bottles/frontend/ui/details-preferences.blp:108 msgid "Manage FidelityFX Super Resolution settings" msgstr "" #: bottles/frontend/ui/details-preferences.blp:125 -#, fuzzy msgid "Discrete Graphics" -msgstr "GPU chuyên dụng" +msgstr "GPU chuyên dụng (rời)" #: bottles/frontend/ui/details-preferences.blp:126 msgid "" @@ -726,13 +724,15 @@ msgid "" msgstr "" #: bottles/frontend/ui/details-preferences.blp:135 +#, fuzzy msgid "Post-Processing Effects" -msgstr "" +msgstr "Xử lý hậu kỳ" #: bottles/frontend/ui/details-preferences.blp:136 +#, fuzzy msgid "" "Add various post-processing effects using vkBasalt. Only works on Vulkan." -msgstr "" +msgstr "Thêm xử lý hậu kỳ với vkBasalt. Chỉ hoạt động trên Vulkan." #: bottles/frontend/ui/details-preferences.blp:138 #, fuzzy @@ -741,7 +741,7 @@ msgstr "Quản lý thiết đặt Gamescope" #: bottles/frontend/ui/details-preferences.blp:154 msgid "Manage how games should be displayed on the screen using Gamescope." -msgstr "" +msgstr "Quản lý cách các trò chơi hiện thị trên màn hình bằng Gamescope." #: bottles/frontend/ui/details-preferences.blp:157 msgid "Manage Gamescope settings" @@ -811,24 +811,24 @@ msgid "" "Improve loading time when launching the game multiple times. The game will " "take longer to start for the first time." msgstr "" +"Cải thiện thời gian nạp khi trò chơi chạy nhiều lần. Lần đầu tiên chạy sẽ " +"tốn nhiều thời gian." #: bottles/frontend/ui/details-preferences.blp:226 -#, fuzzy msgid "Manage vmtouch settings" -msgstr "Quản lý thiết đặt Gamescope" +msgstr "Quản lý cài đặt vmtouch" #: bottles/frontend/ui/details-preferences.blp:241 msgid "OBS Game Capture" msgstr "" #: bottles/frontend/ui/details-preferences.blp:242 -#, fuzzy msgid "Toggle OBS Game Capture for all Vulkan and OpenGL programs." -msgstr "Tìm kiếm các chương trình đã cài đặt" +msgstr "Sử dụng OBS Game Capture cho toàn bộ chương trình Vulkan và OpenGL" #: bottles/frontend/ui/details-preferences.blp:251 msgid "Compatibility" -msgstr "" +msgstr "Tương thích" #: bottles/frontend/ui/details-preferences.blp:254 #, fuzzy @@ -841,11 +841,11 @@ msgstr "Đang cập nhật phiên bản Windows, vui lòng đợi…" #: bottles/frontend/ui/details-preferences.blp:266 msgid "Language" -msgstr "" +msgstr "Ngôn ngữ" #: bottles/frontend/ui/details-preferences.blp:267 msgid "Choose the language to use with programs." -msgstr "" +msgstr "Chọn ngôn ngữ sẽ được dùng với các chương trình" #: bottles/frontend/ui/details-preferences.blp:275 msgid "Dedicated Sandbox" @@ -866,26 +866,24 @@ msgid "Bottles Runtime" msgstr "Bottles Runtime" #: bottles/frontend/ui/details-preferences.blp:296 -#, fuzzy msgid "" "Provide a bundle of extra libraries for more compatibility. Disable it if " "you run into issues." msgstr "" -"Cung cấp một gói thư viện bổ sung để tương thích hơn,\n" -"vô hiệu hóa nếu bạn gặp sự cố." +"Cung cấp một gói thư viện bổ sung để tương thích hơn, vô hiệu hóa nếu bạn " +"gặp sự cố." #: bottles/frontend/ui/details-preferences.blp:306 msgid "Steam Runtime" msgstr "Steam Runtime" #: bottles/frontend/ui/details-preferences.blp:307 -#, fuzzy msgid "" "Provide a bundle of extra libraries for more compatibility with Steam games. " "Disable it if you run into issues." msgstr "" -"Cung cấp một gói thư viện bổ sung để tương thích hơn,\n" -"vô hiệu hóa nếu bạn gặp sự cố." +"Cung cấp một gói thư viện bổ sung để tương thích hơn với các trò chơi của " +"Steam, vô hiệu hóa nếu bạn gặp sự cố." #: bottles/frontend/ui/details-preferences.blp:315 #: bottles/frontend/ui/dialog-launch-options.blp:83 @@ -898,22 +896,20 @@ msgstr "Thư mục làm việc" #: bottles/frontend/ui/dialog-launch-options.blp:90 #: bottles/frontend/ui/new.blp:150 bottles/frontend/ui/new.blp:181 #: bottles/frontend/ui/preferences.blp:136 -#, fuzzy msgid "Reset to Default" -msgstr "Chi tiết Chai" +msgstr "Tái cài đặt về mặc định" #: bottles/frontend/ui/details-preferences.blp:339 #: bottles/frontend/ui/preferences.blp:157 bottles/frontend/views/new.py:78 #: bottles/frontend/views/preferences.py:210 msgid "(Default)" -msgstr "" +msgstr "(Mặc định)" #: bottles/frontend/ui/details-preferences.blp:347 #: bottles/frontend/ui/dialog-dll-overrides.blp:7 #: bottles/frontend/ui/dialog-dll-overrides.blp:12 -#, fuzzy msgid "DLL Overrides" -msgstr "DLL ghi đè" +msgstr "Ghi đè DLL" #: bottles/frontend/ui/details-preferences.blp:357 #: bottles/frontend/ui/dialog-env-vars.blp:20 @@ -922,9 +918,8 @@ msgid "Environment Variables" msgstr "Biến môi trường" #: bottles/frontend/ui/details-preferences.blp:367 -#, fuzzy msgid "Manage Drives" -msgstr "Tình quản lý thực thi" +msgstr "Quản lý ổ nhớ" #: bottles/frontend/ui/details-preferences.blp:381 #, fuzzy @@ -967,7 +962,7 @@ msgstr "Làm mới" #: bottles/frontend/ui/details-taskmanager.blp:22 msgid "Stop process" -msgstr "" +msgstr "Dừng tiến trình" #: bottles/frontend/ui/details-versioning.blp:18 #, fuzzy @@ -994,9 +989,8 @@ msgid "Create new Snapshot" msgstr "Tạo trạng thái mới" #: bottles/frontend/ui/details.blp:16 -#, fuzzy msgid "Details" -msgstr "Chi tiết Chai" +msgstr "Chi tiết" #: bottles/frontend/ui/details.blp:24 bottles/frontend/ui/details.blp:64 #: bottles/frontend/ui/importer.blp:15 @@ -1100,13 +1094,12 @@ msgid "Quit" msgstr "Thoát" #: bottles/frontend/ui/dialog-dll-overrides.blp:11 -#, fuzzy msgid "" "Dynamic Link Libraries can be specified to be builtin (provided by Wine) or " "native (provided by the program)." msgstr "" "Thư viện Liên kết Động (DLL) có thể được chỉ định là tích hợp (được cung cấp " -"bởi Wine) hoặc bản địa (được cung cấp bởi chương trình)" +"bởi Wine) hoặc native (được cung cấp bởi chương trình)" #: bottles/frontend/ui/dialog-dll-overrides.blp:15 #, fuzzy @@ -1130,7 +1123,7 @@ msgstr "" #: bottles/frontend/ui/dialog-drives.blp:27 msgid "Letter" -msgstr "" +msgstr "Ký tự" #: bottles/frontend/ui/dialog-drives.blp:49 #, fuzzy @@ -1160,12 +1153,11 @@ msgstr "Đang nhân bản…" #: bottles/frontend/ui/dialog-upgrade-versioning.blp:112 #: bottles/frontend/views/new.py:177 msgid "This could take a while." -msgstr "" +msgstr "Điều này sẽ tốn kha khá thời gian." #: bottles/frontend/ui/dialog-duplicate.blp:97 -#, fuzzy msgid "Bottle Duplicated" -msgstr "Chai được sao chép" +msgstr "Bottle đã được nhân bản" #: bottles/frontend/ui/dialog-env-vars.blp:28 msgid "" @@ -1177,7 +1169,7 @@ msgstr "" #: bottles/frontend/ui/dialog-env-vars.blp:31 msgid "Variable Name" -msgstr "" +msgstr "Tên biến" #: bottles/frontend/ui/dialog-env-vars.blp:37 #, fuzzy @@ -1255,7 +1247,7 @@ msgstr "" #: bottles/frontend/ui/dialog-gamescope.blp:121 msgid "Frame Rate Limit" -msgstr "" +msgstr "Giới hạn khung hình" #: bottles/frontend/ui/dialog-gamescope.blp:137 msgid "Frame Rate Limit When Unfocused" @@ -1273,20 +1265,19 @@ msgstr "Độ rộng của cửa sổ" #: bottles/frontend/ui/dialog-gamescope.blp:166 msgid "Borderless" -msgstr "" +msgstr "Không viền" #: bottles/frontend/ui/dialog-gamescope.blp:172 msgid "Fullscreen" -msgstr "" +msgstr "Toàn màn hình" #: bottles/frontend/ui/dialog-installer.blp:40 msgid "Do you want to proceed with the installation?" msgstr "" #: bottles/frontend/ui/dialog-installer.blp:45 -#, fuzzy msgid "Start Installation" -msgstr "Hoạt động" +msgstr "Bắt đầu cài đặt" #: bottles/frontend/ui/dialog-installer.blp:64 msgid "" @@ -1296,7 +1287,7 @@ msgstr "" #: bottles/frontend/ui/dialog-installer.blp:68 msgid "Proceed" -msgstr "" +msgstr "Đã chạy" #: bottles/frontend/ui/dialog-installer.blp:127 #, fuzzy @@ -1318,9 +1309,8 @@ msgid "Something went wrong." msgstr "" #: bottles/frontend/ui/dialog-journal.blp:9 -#, fuzzy msgid "All messages" -msgstr "Xóa tin nhắn" +msgstr "Toàn bộ tin nhắn" #: bottles/frontend/ui/dialog-journal.blp:13 msgid "Critical" @@ -1411,23 +1401,20 @@ msgid "Preferences Overrides" msgstr "Tùy chọn" #: bottles/frontend/ui/dialog-launch-options.blp:119 -#, fuzzy msgid "Reset to Bottle's Defaults" -msgstr "Chi tiết Chai" +msgstr "Tái cài đặt về mặc định" #: bottles/frontend/ui/dialog-launch-options.blp:165 -#, fuzzy msgid "Virtual Desktop" -msgstr "Sử dụng máy tính ảo" +msgstr "Sử dụng desktop ảo" #: bottles/frontend/ui/dialog-proton-alert.blp:4 msgid "Proton Disclaimer" msgstr "" #: bottles/frontend/ui/dialog-proton-alert.blp:21 -#, fuzzy msgid "Use Proton" -msgstr "ProtonDB" +msgstr "Dùng Proton" #: bottles/frontend/ui/dialog-proton-alert.blp:35 msgid "" @@ -1454,12 +1441,11 @@ msgstr "Đổi tên" #: bottles/frontend/ui/dialog-rename.blp:30 msgid "Choose a new name for the selected program." -msgstr "" +msgstr "Nhập tên mới cho chương trình đang chọn." #: bottles/frontend/ui/dialog-rename.blp:33 -#, fuzzy msgid "New Name" -msgstr "Tên" +msgstr "Tên mới" #: bottles/frontend/ui/dialog-run-args.blp:13 #, fuzzy @@ -1477,23 +1463,20 @@ msgid "Write below the arguments to be passed to the executable." msgstr "Viết các đối số sẽ được thực thi dưới đây." #: bottles/frontend/ui/dialog-run-args.blp:47 -#, fuzzy msgid "e.g.: -opengl -SkipBuildPatchPrereq" -msgstr "vd: -opengl -Bỏ_qua_Bản_vá_Trước" +msgstr "vd: -opengl -SkipBuildPatchPrereq" #: bottles/frontend/ui/dialog-sandbox.blp:7 -#, fuzzy msgid "Sandbox Settings" -msgstr "Quản lý thiết đặt Gamescope" +msgstr "Thiết lập sandbox" #: bottles/frontend/ui/dialog-sandbox.blp:25 msgid "Share Network" msgstr "" #: bottles/frontend/ui/dialog-sandbox.blp:34 -#, fuzzy msgid "Share Sound" -msgstr "Không tìm thấy trạng thái nào" +msgstr "" #: bottles/frontend/ui/dialog-upgrade-versioning.blp:16 msgid "Upgrade Needed" @@ -1509,9 +1492,8 @@ msgid "Launch upgrade" msgstr "" #: bottles/frontend/ui/dialog-upgrade-versioning.blp:66 -#, fuzzy msgid "New Versioning System" -msgstr "Trình phiên bản" +msgstr "" #: bottles/frontend/ui/dialog-upgrade-versioning.blp:69 msgid "The new bottle versioning system has landed." From d192da2e8434e1bff68aad7b76a59ae6298f90fd Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Fri, 31 Jan 2025 15:31:11 -0500 Subject: [PATCH 066/146] flatpak: Update libadwaita to 1.7.beta --- build-aux/com.usebottles.bottles.Devel.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build-aux/com.usebottles.bottles.Devel.json b/build-aux/com.usebottles.bottles.Devel.json index 21c31172ca4..55a19a9e4a7 100644 --- a/build-aux/com.usebottles.bottles.Devel.json +++ b/build-aux/com.usebottles.bottles.Devel.json @@ -360,8 +360,8 @@ { "type": "git", "url": "https://gitlab.gnome.org/GNOME/libadwaita.git", - "tag": "1.7.alpha", - "commit": "f4b0068b2ef8db3a582eda08eacbaa8ceac3ef3a" + "tag": "1.7.beta", + "commit": "10dbadc7a770f36e20d5053e6b08676bc36f7957" } ] }, From b327ce9dfcc72ac16e7e51208932ec44055739d8 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Fri, 31 Jan 2025 15:31:39 -0500 Subject: [PATCH 067/146] flatpak: Remove runtime This isn't needed anymore. --- build-aux/com.usebottles.bottles.Devel.json | 22 --------------------- 1 file changed, 22 deletions(-) diff --git a/build-aux/com.usebottles.bottles.Devel.json b/build-aux/com.usebottles.bottles.Devel.json index 55a19a9e4a7..74040d30b8d 100644 --- a/build-aux/com.usebottles.bottles.Devel.json +++ b/build-aux/com.usebottles.bottles.Devel.json @@ -280,28 +280,6 @@ } ] }, - { - "name": "runtime", - "buildsystem": "simple", - "build-commands": [ - "mkdir -p /app/etc/runtime", - "cp -a * /app/etc/runtime/" - ], - "sources": [ - { - "type": "archive", - "url": "https://github.com/bottlesdevs/runtime/releases/download/0.6.3/runtime-0.6.3.tar.gz", - "sha256": "d7749b48927bd782e128e372a1d7085133fbe300eb9193134eb821f61bc5fad6", - "x-checker-data": { - "type": "json", - "is-important": true, - "url": "https://api.github.com/repos/bottlesdevs/runtime/releases/latest", - "version-query": ".tag_name", - "url-query": "https://github.com/bottlesdevs/runtime/releases/download/$version/runtime-$version.tar.gz" - } - } - ] - }, { "name": "fluidsynth", "buildsystem": "cmake-ninja", From 85ed94c0a93269eec36f8133c1da0358da073881 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Fri, 31 Jan 2025 15:34:27 -0500 Subject: [PATCH 068/146] flatpak: Update vte to 0.78.3 --- build-aux/com.usebottles.bottles.Devel.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build-aux/com.usebottles.bottles.Devel.json b/build-aux/com.usebottles.bottles.Devel.json index 74040d30b8d..1a52224b195 100644 --- a/build-aux/com.usebottles.bottles.Devel.json +++ b/build-aux/com.usebottles.bottles.Devel.json @@ -269,8 +269,8 @@ { "type": "git", "url": "https://gitlab.gnome.org/GNOME/vte", - "tag": "0.78.0", - "commit": "00c99e846bf83536f978b4fe5dc2c8a6983b8a94", + "tag": "0.78.3", + "commit": "6f293fa50a52c79a47642875a534dacaf3913a55", "x-checker-data": { "type": "git", "tag-pattern": "^([\\d.]+)$" From 930cc3f15cc2d754303173e7438b92ecb99907cf Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Fri, 31 Jan 2025 15:37:39 -0500 Subject: [PATCH 069/146] flatpak: Update blueprint-compiler to 0.16.0 --- build-aux/com.usebottles.bottles.Devel.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build-aux/com.usebottles.bottles.Devel.json b/build-aux/com.usebottles.bottles.Devel.json index 1a52224b195..0cfcda554ce 100644 --- a/build-aux/com.usebottles.bottles.Devel.json +++ b/build-aux/com.usebottles.bottles.Devel.json @@ -210,8 +210,8 @@ { "type": "git", "url": "https://gitlab.gnome.org/jwestman/blueprint-compiler", - "tag": "v0.14.0", - "commit": "8e10fcf8692108b9d4ab78f41086c5d7773ef864", + "tag": "v0.16.0", + "commit": "04ef0944db56ab01307a29aaa7303df6067cb3c0", "x-checker-data": { "type": "git", "tag-pattern": "^v([\\d.]+)$" From 737dd41b680c22075c58062125557b837e0675f8 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Fri, 31 Jan 2025 15:38:08 -0500 Subject: [PATCH 070/146] flatpak: Update libportal to 0.9.0 --- build-aux/com.usebottles.bottles.Devel.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build-aux/com.usebottles.bottles.Devel.json b/build-aux/com.usebottles.bottles.Devel.json index 0cfcda554ce..28ccb9170cb 100644 --- a/build-aux/com.usebottles.bottles.Devel.json +++ b/build-aux/com.usebottles.bottles.Devel.json @@ -193,8 +193,8 @@ { "type": "git", "url": "https://github.com/flatpak/libportal", - "tag": "0.8.1", - "commit": "26c15008cbe579f57f89468384f8efc033f25f6f", + "tag": "0.9.0", + "commit": "731e7410fa5765e7c4eb76a51140a19637620c13", "x-checker-data": { "type": "git", "is-important": true, From 52338cabebb4c038b529e45aab707fb6aba10031 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Fri, 31 Jan 2025 15:38:40 -0500 Subject: [PATCH 071/146] flatpak: Update ImageMagick to 7.1.1-43 --- build-aux/com.usebottles.bottles.Devel.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build-aux/com.usebottles.bottles.Devel.json b/build-aux/com.usebottles.bottles.Devel.json index 28ccb9170cb..d6d1b289eb1 100644 --- a/build-aux/com.usebottles.bottles.Devel.json +++ b/build-aux/com.usebottles.bottles.Devel.json @@ -170,8 +170,8 @@ { "type": "git", "url": "https://github.com/ImageMagick/ImageMagick", - "tag": "7.1.1-38", - "commit": "b0ab92265bab638e6ecd2f18b45977c38771c671", + "tag": "7.1.1-43", + "commit": "a2d96f40e707ba54b57e7d98c3277d3ea6611ace", "x-checker-data": { "type": "git", "tag-pattern": "^([\\d.]+-[\\d]+)$" From 20932469ea732ee00609a3d3b9eed640959bec8f Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Sat, 1 Feb 2025 23:30:58 -0500 Subject: [PATCH 072/146] flatpak: Update vulkan-tools to vulkan-sdk-1.4.304.0 --- build-aux/com.usebottles.bottles.Devel.json | 26 ++++++++++++++++----- 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/build-aux/com.usebottles.bottles.Devel.json b/build-aux/com.usebottles.bottles.Devel.json index d6d1b289eb1..560359371bd 100644 --- a/build-aux/com.usebottles.bottles.Devel.json +++ b/build-aux/com.usebottles.bottles.Devel.json @@ -114,15 +114,29 @@ { "type": "git", "url": "https://github.com/KhronosGroup/Vulkan-Tools.git", - "tag": "sdk-1.3.261.1", - "commit": "a7da7027ca9fd0901639f02619c226da9c6036f1", + "tag": "vulkan-sdk-1.4.304.0", + "commit": "4c25e78dd87720275ab069de1fe2e005cd528ed9", "x-checker-data": { "type": "git", - "tag-pattern": "^sdk-([\\d.]+)$" + "tag-pattern": "^vulkan-sdk-([\\d.]+)$" } } ], "modules": [ + { + "name": "volk", + "buildsystem": "cmake-ninja", + "config-opts": [ + "-DVOLK_INSTALL=ON" + ], + "sources": [ + { + "type": "archive", + "url": "https://github.com/zeux/volk/archive/refs/tags/1.4.304.tar.gz", + "sha256": "ab3d4a8ccaeb32652259cdd008399504a41792675b0421d90b67729ee274746f" + } + ] + }, { "name": "vulkan-headers", "buildsystem": "cmake-ninja", @@ -130,11 +144,11 @@ { "type": "git", "url": "https://github.com/KhronosGroup/Vulkan-Headers.git", - "tag": "sdk-1.3.261.1", - "commit": "85c2334e92e215cce34e8e0ed8b2dce4700f4a50", + "tag": "vulkan-sdk-1.4.304.0", + "commit": "d4a196d8c84e032d27f999adcea3075517c1c97f", "x-checker-data": { "type": "git", - "tag-pattern": "^sdk-([\\d.]+)$" + "tag-pattern": "^vulkan-sdk-([\\d.]+)$" } } ] From b8fb76de49d456fcc0f4160cd8a8bbb98a9bfdf2 Mon Sep 17 00:00:00 2001 From: David Yantis <404NetworkError@users.noreply.github.com> Date: Mon, 3 Feb 2025 17:55:37 -0500 Subject: [PATCH 073/146] Remove NVIDIA Flatpak Workaround (#3726) revert: Duplicated NVIDIA GPUs Fixed by flathub/org.freedesktop.Platform.GL.nvidia#331 --- bottles/backend/utils/vulkan.py | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/bottles/backend/utils/vulkan.py b/bottles/backend/utils/vulkan.py index 0b667cee1a0..9607abb9dec 100644 --- a/bottles/backend/utils/vulkan.py +++ b/bottles/backend/utils/vulkan.py @@ -19,7 +19,6 @@ from glob import glob import shutil import subprocess -import filecmp class VulkanUtils: @@ -46,17 +45,7 @@ def __get_vk_icd_loaders(self): for file in _files: if "nvidia" in file.lower(): - # Workaround for nvidia flatpak bug: https://github.com/flathub/org.freedesktop.Platform.GL.nvidia/issues/112 - should_skip = False - for nvidia_loader in loaders["nvidia"]: - try: - if filecmp.cmp(nvidia_loader, file): - should_skip = True - continue - except: - pass - if not should_skip: - loaders["nvidia"] += [file] + loaders["nvidia"] += [file] elif "amd" in file.lower() or "radeon" in file.lower(): loaders["amd"] += [file] elif "intel" in file.lower(): From 723679cbe8dd3f8a9e5c2417fe580131835f3fe4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sabri=20=C3=9Cnal?= <161761531+yakushabb@users.noreply.github.com> Date: Tue, 4 Feb 2025 16:43:18 +0300 Subject: [PATCH 074/146] appdata: `translate=no` properties (#3327) appdata: translate=no properties It appears that the appstream project no longer supports `translatable=no` properties, and gettext extract the `translatable=no` marked strings as translatable. I opened an issue to inform about the situation, but `translatable=no` properties are not accepted by developers. You can find the issue here: https://github.com/ximion/appstream/issues/623 --- .../com.usebottles.bottles.metainfo.xml.in.in | 44 +++++++++---------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/data/com.usebottles.bottles.metainfo.xml.in.in b/data/com.usebottles.bottles.metainfo.xml.in.in index 4a337b219ed..7d5027bbcb3 100644 --- a/data/com.usebottles.bottles.metainfo.xml.in.in +++ b/data/com.usebottles.bottles.metainfo.xml.in.in @@ -7,7 +7,7 @@ Bottles Run Windows software - The Bottles Contributors + The Bottles Contributors #f4c8cb @@ -77,7 +77,7 @@ - +
  • Add Ctrl+N shortcut for creating a new bottle
  • Add Shortcuts window
  • @@ -91,12 +91,12 @@ - +

    Fixed a regression that makes the bottle's preferences page blank in some cases

    - +

    Fixed an issue where clicking on a snapshot instantly started the restore process

    Fixed a crash in bottles-cli when neither --executable nor --program was specified

    Fixed an issue where launch options were not honored when applications were launched from Desktop Entries

    @@ -111,12 +111,12 @@
    - +

    Fixed a bug where the "win11" option was not available

    - +

    New "Native" Force Stop all Processes option

    Provide bottle Path as env var

    Fix "bottles:run/" uri processing (#3444)

    @@ -131,12 +131,12 @@
    - +

    Fixed crash on starting executables via the file manager [#3427]

    - +

    Support d3d8 via dxvk

    Removed @lru_cache decorator from the Paths class, plus minor typing fixes

    Fixed crash on startup [#3329]

    @@ -154,7 +154,7 @@
    - +

    Fix running programs via CLI

    Fix handling of empty program arguments

    Removed obsolete faudio dependency from the environment

    @@ -163,7 +163,7 @@
    - +

    Clean FSR settings

    Improve bad connections handling

    Update Flatpak runtime

    @@ -172,18 +172,18 @@
    - +

    Fix runners and components from not showing when prereleases are off

    Fix Steam runtime compatibility with Wine runners

    - +

    A few bug fixes

    - +

    Support for the double-DLL VKD3D

    Updated Flatpak runtime

    Minor improvement and fixes to the library

    @@ -193,34 +193,34 @@
    - +

    Update metadata information

    - +

    Add more update information and correct release notes version

    - +

    Fixed "Add to Steam" button

    Fixed BottleConfig being not serializable

    Fixed Patool double extraction failing

    - +

    Correct version

    - +

    Fix crash when creating a bottle

    - +

    Major change: Redesign New Bottle interface

    Quality of life improvements:

      @@ -238,14 +238,14 @@ - +
      • Fix error when downloading if Bottles isn't run from terminal
      - +
      • Correct version date
      • Hide NVIDIA-related critical errors on non-NVIDIA systems
      • @@ -253,7 +253,7 @@ - +
        • Gamescope improvements and fixes
        • Dependency installation is faster and more stable
        • From 0967184644d412a63c9c89248cd36fc95ed5edf9 Mon Sep 17 00:00:00 2001 From: GNUgenius Date: Wed, 5 Feb 2025 02:22:25 +0400 Subject: [PATCH 075/146] frontend: Added 'Failed adding to Steam Library dialog' in program_row.py' dialog (#3730) frontend: Added 'Failed adding to Steam Library dialog' in program_row.py --- bottles/frontend/program_row.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/bottles/frontend/program_row.py b/bottles/frontend/program_row.py index 620cd041e57..ff6c8591db5 100644 --- a/bottles/frontend/program_row.py +++ b/bottles/frontend/program_row.py @@ -339,6 +339,10 @@ def update(result, _error=False): self.window.show_toast( _('"{0}" added to your Steam library').format(self.program["name"]) ) + else: + self.window.show_toast( + _('"{0}" failed adding to your Steam library').format(self.program["name"]) + ) steam_manager = SteamManager(self.config) RunAsync( From 38a2ff41be33bce003bd19c731304976bee5ab45 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Sun, 9 Feb 2025 14:25:21 -0500 Subject: [PATCH 076/146] program-row: Run formatter --- bottles/frontend/program_row.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bottles/frontend/program_row.py b/bottles/frontend/program_row.py index ff6c8591db5..d73f272608c 100644 --- a/bottles/frontend/program_row.py +++ b/bottles/frontend/program_row.py @@ -341,7 +341,9 @@ def update(result, _error=False): ) else: self.window.show_toast( - _('"{0}" failed adding to your Steam library').format(self.program["name"]) + _('"{0}" failed adding to your Steam library').format( + self.program["name"] + ) ) steam_manager = SteamManager(self.config) From 420088fd1a54605ee925b4f0a61f350bcc328ba5 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Sun, 9 Feb 2025 14:15:08 -0500 Subject: [PATCH 077/146] ci: Update image and action References: - https://github.com/getting-things-gnome/gtg/pull/1187 - https://github.com/flathub-infra/flatpak-github-actions/ --- .github/workflows/build_flatpak.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build_flatpak.yml b/.github/workflows/build_flatpak.yml index 8e480c2c471..a38377ae793 100644 --- a/.github/workflows/build_flatpak.yml +++ b/.github/workflows/build_flatpak.yml @@ -8,11 +8,11 @@ jobs: name: "build-packages" runs-on: ubuntu-latest container: - image: bilelmoussaoui/flatpak-github-actions:gnome-47 + image: ghcr.io/flathub-infra/flatpak-github-actions:gnome-47 options: --privileged steps: - uses: actions/checkout@v4 - - uses: bilelmoussaoui/flatpak-github-actions/flatpak-builder@v6 + - uses: flathub-infra/flatpak-github-actions/flatpak-builder@master with: bundle: bottles.flatpak manifest-path: build-aux/com.usebottles.bottles.Devel.json From 3e1dc5bd6e45364bb93b9c0daeab40b98298a358 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Fri, 21 Feb 2025 13:46:28 +0530 Subject: [PATCH 078/146] chore: Update dependency list updater --- .github/workflows/update-manifest.yml | 6 +++--- CODING_GUIDE.md | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/update-manifest.yml b/.github/workflows/update-manifest.yml index 73b1f92b80c..4457f7451a2 100644 --- a/.github/workflows/update-manifest.yml +++ b/.github/workflows/update-manifest.yml @@ -37,11 +37,11 @@ jobs: git config user.name "github-actions[bot]" pur -r requirements.txt pur -r requirements.dev.txt - req2flatpak --requirements-file requirements.txt --yaml --target-platforms 312-x86_64 -o com.usebottles.bottles.pypi-deps.yaml - git diff ${{ github.ref_name }} --exit-code requirements.txt requirements.dev.txt com.usebottles.bottles.pypi-deps.yaml + req2flatpak --requirements-file requirements.txt --yaml --target-platforms 312-x86_64 -o pypi-deps.yaml + git diff ${{ github.ref_name }} --exit-code requirements.txt requirements.dev.txt pypi-deps.yaml updated=$? if [ $updated -ne 0 ]; then - git add requirements.txt requirements.dev.txt com.usebottles.bottles.pypi-deps.yaml + git add requirements.txt requirements.dev.txt pypi-deps git commit -m "Update PyPI dependencies" fi diff --git a/CODING_GUIDE.md b/CODING_GUIDE.md index e05f07f6a74..f34943c5c8f 100644 --- a/CODING_GUIDE.md +++ b/CODING_GUIDE.md @@ -33,7 +33,7 @@ pytest . Regenerate PYPI dependency manifest when requirements.txt changed ```bash -python ./build-aux/flatpak-pip-generator.py --runtime org.gnome.Sdk -r requirements.txt -o com.usebottles.bottles.pypi-deps --yaml +python ./build-aux/flatpak-pip-generator.py --runtime org.gnome.Sdk -r requirements.txt -o build-aux/pypi-deps --yaml ``` ## I18n files From a8fa3b3b2090cdcfcc19fce6aef190d3efc1653b Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Thu, 6 Mar 2025 05:45:51 -0500 Subject: [PATCH 079/146] bottle-preferences: Split toggle feature callback This is important to have because complex toggles require slightly different parameters. Fixes https://github.com/bottlesdevs/Bottles/issues/3720 --- bottles/frontend/details_preferences_page.py | 85 +++++++++++--------- 1 file changed, 47 insertions(+), 38 deletions(-) diff --git a/bottles/frontend/details_preferences_page.py b/bottles/frontend/details_preferences_page.py index b08dc861aeb..ce58232e3fb 100644 --- a/bottles/frontend/details_preferences_page.py +++ b/bottles/frontend/details_preferences_page.py @@ -226,25 +226,29 @@ def __init__(self, details, config, **kwargs): ) self.btn_cwd.connect("clicked", self.choose_cwd) self.btn_cwd_reset.connect("clicked", self.reset_cwd, True) - self.switch_mangohud.connect("state-set", self.__toggle_feature, "mangohud") - self.switch_obsvkc.connect("state-set", self.__toggle_feature, "obsvkc") - self.switch_vkbasalt.connect("state-set", self.__toggle_feature, "vkbasalt") - self.switch_fsr.connect("state-set", self.__toggle_feature, "fsr") + self.switch_mangohud.connect("state-set", self.__toggle_feature_cb, "mangohud") + self.switch_obsvkc.connect("state-set", self.__toggle_feature_cb, "obsvkc") + self.switch_vkbasalt.connect("state-set", self.__toggle_feature_cb, "vkbasalt") + self.switch_fsr.connect("state-set", self.__toggle_feature_cb, "fsr") self.switch_nvapi.connect("state-set", self.__toggle_nvapi) - self.switch_gamemode.connect("state-set", self.__toggle_feature, "gamemode") - self.switch_gamescope.connect("state-set", self.__toggle_feature, "gamescope") - self.switch_sandbox.connect("state-set", self.__toggle_feature, "sandbox") - self.switch_discrete.connect("state-set", self.__toggle_feature, "discrete_gpu") + self.switch_gamemode.connect("state-set", self.__toggle_feature_cb, "gamemode") + self.switch_gamescope.connect( + "state-set", self.__toggle_feature_cb, "gamescope" + ) + self.switch_sandbox.connect("state-set", self.__toggle_feature_cb, "sandbox") + self.switch_discrete.connect( + "state-set", self.__toggle_feature_cb, "discrete_gpu" + ) self.switch_versioning_compression.connect( "state-set", self.__toggle_versioning_compression ) self.switch_auto_versioning.connect( - "state-set", self.__toggle_feature, "versioning_automatic" + "state-set", self.__toggle_feature_cb, "versioning_automatic" ) self.switch_versioning_patterns.connect( - "state-set", self.__toggle_feature, "versioning_exclusion_patterns" + "state-set", self.__toggle_feature_cb, "versioning_exclusion_patterns" ) - self.switch_vmtouch.connect("state-set", self.__toggle_feature, "vmtouch") + self.switch_vmtouch.connect("state-set", self.__toggle_feature_cb, "vmtouch") self.combo_runner.connect("notify::selected", self.__set_runner) self.combo_dxvk.connect("notify::selected", self.__set_dxvk) self.combo_vkd3d.connect("notify::selected", self.__set_vkd3d) @@ -265,7 +269,7 @@ def __init__(self, details, config, **kwargs): if RuntimeManager.get_runtimes("steam"): self.row_steam_runtime.set_visible(True) self.switch_steam_runtime.connect( - "state-set", self.__toggle_feature, "use_steam_runtime" + "state-set", self.__toggle_feature_cb, "use_steam_runtime" ) """Toggle some utilities according to its availability""" @@ -406,22 +410,22 @@ def set_config(self, config: BottleConfig): parameters = self.config.Parameters # temporary lock functions connected to the widgets - self.switch_mangohud.handler_block_by_func(self.__toggle_feature) + self.switch_mangohud.handler_block_by_func(self.__toggle_feature_cb) self.switch_nvapi.handler_block_by_func(self.__toggle_nvapi) - self.switch_vkbasalt.handler_block_by_func(self.__toggle_feature) - self.switch_fsr.handler_block_by_func(self.__toggle_feature) - self.switch_obsvkc.handler_block_by_func(self.__toggle_feature) - self.switch_gamemode.handler_block_by_func(self.__toggle_feature) - self.switch_gamescope.handler_block_by_func(self.__toggle_feature) - self.switch_sandbox.handler_block_by_func(self.__toggle_feature) - self.switch_discrete.handler_block_by_func(self.__toggle_feature) + self.switch_vkbasalt.handler_block_by_func(self.__toggle_feature_cb) + self.switch_fsr.handler_block_by_func(self.__toggle_feature_cb) + self.switch_obsvkc.handler_block_by_func(self.__toggle_feature_cb) + self.switch_gamemode.handler_block_by_func(self.__toggle_feature_cb) + self.switch_gamescope.handler_block_by_func(self.__toggle_feature_cb) + self.switch_sandbox.handler_block_by_func(self.__toggle_feature_cb) + self.switch_discrete.handler_block_by_func(self.__toggle_feature_cb) self.switch_versioning_compression.handler_block_by_func( self.__toggle_versioning_compression ) - self.switch_auto_versioning.handler_block_by_func(self.__toggle_feature) - self.switch_versioning_patterns.handler_block_by_func(self.__toggle_feature) + self.switch_auto_versioning.handler_block_by_func(self.__toggle_feature_cb) + self.switch_versioning_patterns.handler_block_by_func(self.__toggle_feature_cb) with contextlib.suppress(TypeError): - self.switch_steam_runtime.handler_block_by_func(self.__toggle_feature) + self.switch_steam_runtime.handler_block_by_func(self.__toggle_feature_cb) self.combo_runner.handler_block_by_func(self.__set_runner) self.combo_dxvk.handler_block_by_func(self.__set_dxvk) self.combo_vkd3d.handler_block_by_func(self.__set_vkd3d) @@ -540,22 +544,24 @@ def set_config(self, config: BottleConfig): self.combo_sync.set_selected(sync_types.index(sync)) # unlock functions connected to the widgets - self.switch_mangohud.handler_unblock_by_func(self.__toggle_feature) + self.switch_mangohud.handler_unblock_by_func(self.__toggle_feature_cb) self.switch_nvapi.handler_unblock_by_func(self.__toggle_nvapi) - self.switch_vkbasalt.handler_unblock_by_func(self.__toggle_feature) - self.switch_fsr.handler_unblock_by_func(self.__toggle_feature) - self.switch_obsvkc.handler_unblock_by_func(self.__toggle_feature) - self.switch_gamemode.handler_unblock_by_func(self.__toggle_feature) - self.switch_gamescope.handler_unblock_by_func(self.__toggle_feature) - self.switch_sandbox.handler_unblock_by_func(self.__toggle_feature) - self.switch_discrete.handler_unblock_by_func(self.__toggle_feature) + self.switch_vkbasalt.handler_unblock_by_func(self.__toggle_feature_cb) + self.switch_fsr.handler_unblock_by_func(self.__toggle_feature_cb) + self.switch_obsvkc.handler_unblock_by_func(self.__toggle_feature_cb) + self.switch_gamemode.handler_unblock_by_func(self.__toggle_feature_cb) + self.switch_gamescope.handler_unblock_by_func(self.__toggle_feature_cb) + self.switch_sandbox.handler_unblock_by_func(self.__toggle_feature_cb) + self.switch_discrete.handler_unblock_by_func(self.__toggle_feature_cb) self.switch_versioning_compression.handler_unblock_by_func( self.__toggle_versioning_compression ) - self.switch_auto_versioning.handler_unblock_by_func(self.__toggle_feature) - self.switch_versioning_patterns.handler_unblock_by_func(self.__toggle_feature) + self.switch_auto_versioning.handler_unblock_by_func(self.__toggle_feature_cb) + self.switch_versioning_patterns.handler_unblock_by_func( + self.__toggle_feature_cb + ) with contextlib.suppress(TypeError): - self.switch_steam_runtime.handler_unblock_by_func(self.__toggle_feature) + self.switch_steam_runtime.handler_unblock_by_func(self.__toggle_feature_cb) self.combo_runner.handler_unblock_by_func(self.__set_runner) self.combo_dxvk.handler_unblock_by_func(self.__set_dxvk) self.combo_vkd3d.handler_unblock_by_func(self.__set_vkd3d) @@ -582,12 +588,15 @@ def __show_feature_dialog(self, _widget: Gtk.Widget, dialog: Adw.Window) -> None window = dialog(window=self.window, config=self.config) window.present() - def __toggle_feature(self, _widget: Gtk.Widget, state: bool, key: str) -> None: + def __toggle_feature(self, state: bool, key: str) -> None: """Toggle a specific feature.""" self.config = self.manager.update_config( config=self.config, key=key, value=state, scope="Parameters" ).data["config"] + def __toggle_feature_cb(self, _widget: Gtk.Widget, state: bool, key: str) -> None: + self.__toggle_feature(state=state, key=key) + def __set_sync_type(self, *_args): """ Set the sync type (wine, esync, fsync) @@ -622,7 +631,7 @@ def __toggle_nvapi(self, widget=False, state=False): remove=not state, ) - self.__toggle_feature(widget=None, state=state, key="dxvk_nvapi") + self.__toggle_feature(state=state, key="dxvk_nvapi") def __toggle_versioning_compression(self, widget, state): """Toggle the versioning compression for current bottle""" @@ -686,11 +695,11 @@ def update(result: Result[dict], error=False): self.config = result.data["config"] if self.config.Parameters.use_steam_runtime: self.switch_steam_runtime.handler_block_by_func( - self.__toggle_feature + self.__toggle_feature_cb ) self.switch_steam_runtime.set_active(True) self.switch_steam_runtime.handler_unblock_by_func( - self.__toggle_feature + self.__toggle_feature_cb ) set_widgets_status(True) From 987502953991f29b7bda250614173c238206a7ff Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Sat, 8 Mar 2025 16:05:37 -0500 Subject: [PATCH 080/146] Revert "flatpak: Remove runtime" This reverts commit b327ce9dfcc72ac16e7e51208932ec44055739d8. --- build-aux/com.usebottles.bottles.Devel.json | 22 +++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/build-aux/com.usebottles.bottles.Devel.json b/build-aux/com.usebottles.bottles.Devel.json index 560359371bd..3be28dc103b 100644 --- a/build-aux/com.usebottles.bottles.Devel.json +++ b/build-aux/com.usebottles.bottles.Devel.json @@ -294,6 +294,28 @@ } ] }, + { + "name": "runtime", + "buildsystem": "simple", + "build-commands": [ + "mkdir -p /app/etc/runtime", + "cp -a * /app/etc/runtime/" + ], + "sources": [ + { + "type": "archive", + "url": "https://github.com/bottlesdevs/runtime/releases/download/0.6.3/runtime-0.6.3.tar.gz", + "sha256": "d7749b48927bd782e128e372a1d7085133fbe300eb9193134eb821f61bc5fad6", + "x-checker-data": { + "type": "json", + "is-important": true, + "url": "https://api.github.com/repos/bottlesdevs/runtime/releases/latest", + "version-query": ".tag_name", + "url-query": "https://github.com/bottlesdevs/runtime/releases/download/$version/runtime-$version.tar.gz" + } + } + ] + }, { "name": "fluidsynth", "buildsystem": "cmake-ninja", From f6e9196fa2c303d9e194a169a8ee78510edf67c5 Mon Sep 17 00:00:00 2001 From: Giannis Lagodimos <62063308+lagodimos@users.noreply.github.com> Date: Mon, 10 Mar 2025 22:54:35 +0000 Subject: [PATCH 081/146] fix: use correct wine path on 10.2 and above (#3800) --- bottles/backend/wine/winecommand.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bottles/backend/wine/winecommand.py b/bottles/backend/wine/winecommand.py index bf89ff2a6d5..ec2be392f4d 100644 --- a/bottles/backend/wine/winecommand.py +++ b/bottles/backend/wine/winecommand.py @@ -477,7 +477,7 @@ def _get_runner_info(self) -> tuple[str, str]: else: runner = f"{runner}/bin/wine" - if arch == "win64": + if arch == "win64" and os.path.exists(f"{runner}64"): runner = f"{runner}64" runner = shlex.quote(runner) # type: ignore From ca52527aca9bb598bca161c5018101705f2a2828 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Sun, 9 Mar 2025 19:29:31 -0400 Subject: [PATCH 082/146] chore: Update dependency list updater (again) --- .github/workflows/update-manifest.yml | 4 ++-- CODING_GUIDE.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/update-manifest.yml b/.github/workflows/update-manifest.yml index 4457f7451a2..b4995159de7 100644 --- a/.github/workflows/update-manifest.yml +++ b/.github/workflows/update-manifest.yml @@ -37,8 +37,8 @@ jobs: git config user.name "github-actions[bot]" pur -r requirements.txt pur -r requirements.dev.txt - req2flatpak --requirements-file requirements.txt --yaml --target-platforms 312-x86_64 -o pypi-deps.yaml - git diff ${{ github.ref_name }} --exit-code requirements.txt requirements.dev.txt pypi-deps.yaml + req2flatpak --requirements-file requirements.txt --yaml --target-platforms 312-x86_64 -o build-aux/pypi-deps.yaml + git diff ${{ github.ref_name }} --exit-code requirements.txt requirements.dev.txt build-aux/pypi-deps.yaml updated=$? if [ $updated -ne 0 ]; then git add requirements.txt requirements.dev.txt pypi-deps diff --git a/CODING_GUIDE.md b/CODING_GUIDE.md index f34943c5c8f..5f2fe4fc53f 100644 --- a/CODING_GUIDE.md +++ b/CODING_GUIDE.md @@ -33,7 +33,7 @@ pytest . Regenerate PYPI dependency manifest when requirements.txt changed ```bash -python ./build-aux/flatpak-pip-generator.py --runtime org.gnome.Sdk -r requirements.txt -o build-aux/pypi-deps --yaml +python ./build-aux/req2flatpak/req2flatpak.py --requirements-file requirements.txt --yaml --target-platforms 312-x86_64 -o build-aux/pypi-deps.yaml ``` ## I18n files From 547fcd8ba9da1290fe6e4fc7ffbc37c4d90308be Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 21 Feb 2025 07:15:41 +0000 Subject: [PATCH 083/146] Update PyPI dependencies --- build-aux/pypi-deps.yaml | 20 ++++++++++---------- requirements.dev.txt | 4 ++-- requirements.txt | 10 +++++----- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/build-aux/pypi-deps.yaml b/build-aux/pypi-deps.yaml index 858f8177043..26f5eee58db 100644 --- a/build-aux/pypi-deps.yaml +++ b/build-aux/pypi-deps.yaml @@ -22,8 +22,8 @@ sources: only-arches: - x86_64 - type: file - url: https://files.pythonhosted.org/packages/a5/32/8f6669fc4798494966bf446c8c4a162e0b5d893dff088afddf76414f70e1/certifi-2024.12.14-py3-none-any.whl - sha256: 1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56 + url: https://files.pythonhosted.org/packages/38/fc/bce832fd4fd99766c04d1ee0eead6b0ec6486fb100ae5e74c1d91292b982/certifi-2025.1.31-py3-none-any.whl + sha256: ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe - type: file url: https://files.pythonhosted.org/packages/38/6f/f5fbc992a329ee4e0f288c1fe0e2ad9485ed064cac731ed2fe47dcc38cbf/chardet-5.2.0-py3-none-any.whl sha256: e1cf59446890a00105fe7b7912492ea04b6e6f06d4b742b2c788469e34c82970 @@ -39,21 +39,21 @@ sources: url: https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl sha256: 946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3 - type: file - url: https://files.pythonhosted.org/packages/5b/73/65d2f0b698df1731e851e3295eb29a5ab8aa06f763f7e4188647a809578d/numpy-2.2.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - sha256: 0349b025e15ea9d05c3d63f9657707a4e1d471128a3b1d876c095f328f8ff7f0 + url: https://files.pythonhosted.org/packages/39/04/78d2e7402fb479d893953fb78fa7045f7deb635ec095b6b4f0260223091a/numpy-2.2.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl + sha256: 3b787adbf04b0db1967798dba8da1af07e387908ed1553a0d6e74c084d1ceafe only-arches: - x86_64 - type: file - url: https://files.pythonhosted.org/packages/48/90/e583d6e29937ec30a164f1d86a0439c1a2477b5aae9f55d94b37a4f5b5f0/orjson-3.10.13-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - sha256: 064b9dbb0217fd64a8d016a8929f2fae6f3312d55ab3036b00b1d17399ab2f3e + url: https://files.pythonhosted.org/packages/fa/da/31543337febd043b8fa80a3b67de627669b88c7b128d9ad4cc2ece005b7a/orjson-3.10.15-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl + sha256: b48f59114fe318f33bbaee8ebeda696d8ccc94c9e90bc27dbe72153094e26f41 only-arches: - x86_64 - type: file - url: https://files.pythonhosted.org/packages/d3/5e/76a9d08b4b4e4583f269cb9f64de267f9aeae0dacef23307f53a14211716/pathvalidate-3.2.1-py3-none-any.whl - sha256: 9a6255eb8f63c9e2135b9be97a5ce08f10230128c4ae7b3e935378b82b22c4c9 + url: https://files.pythonhosted.org/packages/50/14/c5a0e1a947909810fc4c043b84cac472b70e438148d34f5393be1bac663f/pathvalidate-3.2.3-py3-none-any.whl + sha256: 5eaf0562e345d4b6d0c0239d0f690c3bd84d2a9a3c4c73b99ea667401b27bee1 - type: file - url: https://files.pythonhosted.org/packages/a3/68/c1a6597c901b1f750d2fcf562181c18c0d6c284908e4df57f1029d8b8887/patool-3.1.0-py2.py3-none-any.whl - sha256: 401a918bdbf65434fd59c038bdb2c15ff7185675aedddb4494330c3e8e4fe80d + url: https://files.pythonhosted.org/packages/62/fc/fb9db09ca1693e9db2e6593418fd6d085bc6293610089d29ffd02d3a64fd/patool-3.1.3-py2.py3-none-any.whl + sha256: 1f33785dbe1d9917c1bfa6ed589696cc07774f4840d17b7fab8b405bdbab90a6 - type: file url: https://files.pythonhosted.org/packages/54/16/12b82f791c7f50ddec566873d5bdd245baa1491bac11d15ffb98aecc8f8b/pefile-2024.8.26-py3-none-any.whl sha256: 76f8b485dcd3b1bb8166f1128d395fa3d87af26360c2358fb75b80019b957c6f diff --git a/requirements.dev.txt b/requirements.dev.txt index 7f51ebec891..534a6424fb8 100644 --- a/requirements.dev.txt +++ b/requirements.dev.txt @@ -1,7 +1,7 @@ # Updated using pur -r requirements.txt -pytest==8.3.3 +pytest==8.3.4 requirements-parser==0.11.0 -mypy==1.11.2 +mypy==1.15.0 types_Markdown types-PyYAML types-Pygments diff --git a/requirements.txt b/requirements.txt index cf2976c6d36..f9fa4929a23 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,16 +6,16 @@ chardet==5.2.0 requests[use_chardet_on_py3]==2.32.3 Markdown==3.7 icoextract==0.1.5 -patool==3.1.0 -pathvalidate==3.2.1 +patool==3.1.3 +pathvalidate==3.2.3 FVS==0.3.4 -orjson==3.10.13 +orjson==3.10.15 pycairo==1.27.0 PyGObject==3.50.0 charset-normalizer==3.4.1 -numpy==2.2.2 +numpy==2.2.3 pyfluidsynth==1.3.4 idna==3.10 urllib3==2.3.0 -certifi==2024.12.14 +certifi==2025.1.31 pefile==2024.8.26 From d035e3b5a1823684859ed9f078f0dffa88c94ead Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 21 Feb 2025 07:15:48 +0000 Subject: [PATCH 084/146] Update vulkan-headers, vulkan-tools, libportal and vte modules libportal: Update libportal to 0.9.1 vte: Update vte to 0.79.90 vulkan-headers: Update Vulkan-Headers.git to 1.4.309.0 vulkan-tools: Update Vulkan-Tools.git to 1.4.309.0 ImageMagick: Update ImageMagick to 7.1.1-45 fast_float: Add fast_float --- build-aux/com.usebottles.bottles.Devel.json | 40 +++++++++++++-------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/build-aux/com.usebottles.bottles.Devel.json b/build-aux/com.usebottles.bottles.Devel.json index 3be28dc103b..b927d0595a0 100644 --- a/build-aux/com.usebottles.bottles.Devel.json +++ b/build-aux/com.usebottles.bottles.Devel.json @@ -114,8 +114,8 @@ { "type": "git", "url": "https://github.com/KhronosGroup/Vulkan-Tools.git", - "tag": "vulkan-sdk-1.4.304.0", - "commit": "4c25e78dd87720275ab069de1fe2e005cd528ed9", + "tag": "vulkan-sdk-1.4.309.0", + "commit": "bf9fcd2d62ea9eac52e5351c02e35cb61ec5e873", "x-checker-data": { "type": "git", "tag-pattern": "^vulkan-sdk-([\\d.]+)$" @@ -144,8 +144,8 @@ { "type": "git", "url": "https://github.com/KhronosGroup/Vulkan-Headers.git", - "tag": "vulkan-sdk-1.4.304.0", - "commit": "d4a196d8c84e032d27f999adcea3075517c1c97f", + "tag": "vulkan-sdk-1.4.309.0", + "commit": "952f776f6573aafbb62ea717d871cd1d6816c387", "x-checker-data": { "type": "git", "tag-pattern": "^vulkan-sdk-([\\d.]+)$" @@ -184,8 +184,8 @@ { "type": "git", "url": "https://github.com/ImageMagick/ImageMagick", - "tag": "7.1.1-43", - "commit": "a2d96f40e707ba54b57e7d98c3277d3ea6611ace", + "tag": "7.1.1-45", + "commit": "37b3453c6222ae6b9f96418dbc70df225929db7e", "x-checker-data": { "type": "git", "tag-pattern": "^([\\d.]+-[\\d]+)$" @@ -207,8 +207,8 @@ { "type": "git", "url": "https://github.com/flatpak/libportal", - "tag": "0.9.0", - "commit": "731e7410fa5765e7c4eb76a51140a19637620c13", + "tag": "0.9.1", + "commit": "8f5dc8d192f6e31dafe69e35219e3b707bde71ce", "x-checker-data": { "type": "git", "is-important": true, @@ -273,6 +273,18 @@ } ], "modules": [ + { + "name": "fast_float", + "buildsystem": "cmake-ninja", + "sources": [ + { + "type": "git", + "url": "https://github.com/fastfloat/fast_float.git", + "tag": "v8.0.2", + "commit": "50a80a73ab2ab256ba1c3bf86923ddd8b4202bc7" + } + ] + }, { "name": "vte", "buildsystem": "meson", @@ -281,13 +293,13 @@ ], "sources": [ { - "type": "git", - "url": "https://gitlab.gnome.org/GNOME/vte", - "tag": "0.78.3", - "commit": "6f293fa50a52c79a47642875a534dacaf3913a55", + "type": "archive", + "url": "https://download.gnome.org/sources/vte/0.79/vte-0.79.91.tar.xz", + "sha256": "adca667d40ae1839ba258b63701cd05fba249303d72258711cc69294b2cb8646", "x-checker-data": { - "type": "git", - "tag-pattern": "^([\\d.]+)$" + "type": "gnome", + "name": "vte", + "stable-only": true } } ] From ced72cb8e98209bc0015731f0779b7682e688a48 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Fri, 14 Mar 2025 14:53:35 -0400 Subject: [PATCH 085/146] bottle-row: Set can-target and can-focus to false The GtkListBox::row-activated signal only emits when a row is activated, not the child widget. This means, the check button wouldn't trigger the emission of the signal, thereby not updating the NewBottleDialog:selected-environment property. Fixes https://github.com/bottlesdevs/Bottles/issues/3740 --- bottles/frontend/check-row.blp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bottles/frontend/check-row.blp b/bottles/frontend/check-row.blp index b4dda3bf3c6..0e79c8c97c0 100644 --- a/bottles/frontend/check-row.blp +++ b/bottles/frontend/check-row.blp @@ -8,5 +8,7 @@ template $CheckRow: Adw.ActionRow { [prefix] CheckButton check_button { valign: center; + can-focus: false; + can-target: false; } } From b2c6025069288598aac66548ded236deebf02e98 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Sun, 16 Mar 2025 22:30:25 -0400 Subject: [PATCH 086/146] desktop: Add more categories --- data/com.usebottles.bottles.desktop.in.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/com.usebottles.bottles.desktop.in.in b/data/com.usebottles.bottles.desktop.in.in index 536ddbfc052..4bc3e7e87ee 100644 --- a/data/com.usebottles.bottles.desktop.in.in +++ b/data/com.usebottles.bottles.desktop.in.in @@ -6,7 +6,7 @@ Exec=bottles %u TryExec=bottles Terminal=false Type=Application -Categories=Utility;GNOME;GTK; +Categories=Utility;Game;Graphics;3DGraphics;Emulator;GNOME;GTK; StartupNotify=true StartupWMClass=bottles MimeType=x-scheme-handler/bottles;application/x-ms-dos-executable;application/x-msi;application/x-ms-shortcut;application/x-wine-extension-msp; From aafe54b7ffd34dd2b61cf744561479f12bd5a30a Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Sun, 16 Mar 2025 22:41:19 -0400 Subject: [PATCH 087/146] appstream: Add categories --- data/com.usebottles.bottles.metainfo.xml.in.in | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/data/com.usebottles.bottles.metainfo.xml.in.in b/data/com.usebottles.bottles.metainfo.xml.in.in index 7d5027bbcb3..0f49f0fde2e 100644 --- a/data/com.usebottles.bottles.metainfo.xml.in.in +++ b/data/com.usebottles.bottles.metainfo.xml.in.in @@ -9,6 +9,15 @@ The Bottles Contributors + + Utility + Game + Graphics + 3DGraphics + Emulator + GNOME + GTK + #f4c8cb #892119 From 47f8790e267f38dfc21a24e7a1f577009ba3c3b0 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Sun, 16 Mar 2025 22:42:43 -0400 Subject: [PATCH 088/146] desktop: Use sentence case for comment --- data/com.usebottles.bottles.desktop.in.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/com.usebottles.bottles.desktop.in.in b/data/com.usebottles.bottles.desktop.in.in index 4bc3e7e87ee..cd6ed9fb417 100644 --- a/data/com.usebottles.bottles.desktop.in.in +++ b/data/com.usebottles.bottles.desktop.in.in @@ -1,6 +1,6 @@ [Desktop Entry] Name=@APP_NAME@ -Comment=Run Windows Software +Comment=Run Windows software Icon=@APP_ID@ Exec=bottles %u TryExec=bottles From daa3cb5c44d6f34ae18533208225cb163e6aab03 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Sun, 16 Mar 2025 22:45:05 -0400 Subject: [PATCH 089/146] desktop: Add more keywords --- data/com.usebottles.bottles.desktop.in.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/com.usebottles.bottles.desktop.in.in b/data/com.usebottles.bottles.desktop.in.in index cd6ed9fb417..eaf62e01256 100644 --- a/data/com.usebottles.bottles.desktop.in.in +++ b/data/com.usebottles.bottles.desktop.in.in @@ -10,5 +10,5 @@ Categories=Utility;Game;Graphics;3DGraphics;Emulator;GNOME;GTK; StartupNotify=true StartupWMClass=bottles MimeType=x-scheme-handler/bottles;application/x-ms-dos-executable;application/x-msi;application/x-ms-shortcut;application/x-wine-extension-msp; -Keywords=wine;windows; +Keywords=wine;windows;gaming;emulate;emulator;game; X-GNOME-UsesNotifications=true From 8875b2b3c6a73d12d869d1106091876bf6eacf1b Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Wed, 26 Mar 2025 21:14:07 -0400 Subject: [PATCH 090/146] flatpak: Update dependencies --- .github/workflows/build_flatpak.yml | 2 +- build-aux/com.usebottles.bottles.Devel.json | 71 +++++---------------- 2 files changed, 18 insertions(+), 55 deletions(-) diff --git a/.github/workflows/build_flatpak.yml b/.github/workflows/build_flatpak.yml index a38377ae793..f6687a29176 100644 --- a/.github/workflows/build_flatpak.yml +++ b/.github/workflows/build_flatpak.yml @@ -8,7 +8,7 @@ jobs: name: "build-packages" runs-on: ubuntu-latest container: - image: ghcr.io/flathub-infra/flatpak-github-actions:gnome-47 + image: ghcr.io/flathub-infra/flatpak-github-actions:gnome-48 options: --privileged steps: - uses: actions/checkout@v4 diff --git a/build-aux/com.usebottles.bottles.Devel.json b/build-aux/com.usebottles.bottles.Devel.json index b927d0595a0..9d730fea0a1 100644 --- a/build-aux/com.usebottles.bottles.Devel.json +++ b/build-aux/com.usebottles.bottles.Devel.json @@ -4,7 +4,7 @@ "runtime": "org.gnome.Platform", "base": "org.winehq.Wine", "base-version": "stable-24.08", - "runtime-version": "47", + "runtime-version": "48", "command": "bottles", "finish-args": [ "--allow=devel", @@ -33,11 +33,11 @@ "add-extensions": { "org.gnome.Platform.Compat.i386": { "directory": "lib/i386-linux-gnu", - "version": "47" + "version": "48" }, "org.gnome.Platform.Compat.i386.Debug": { "directory": "lib/debug/lib/i386-linux-gnu", - "version": "47", + "version": "48", "no-autodownload": true }, "com.valvesoftware.Steam.CompatibilityTool": { @@ -184,8 +184,8 @@ { "type": "git", "url": "https://github.com/ImageMagick/ImageMagick", - "tag": "7.1.1-45", - "commit": "37b3453c6222ae6b9f96418dbc70df225929db7e", + "tag": "7.1.1-46", + "commit": "8209e844cf02b5365918da83b2fc811442813080", "x-checker-data": { "type": "git", "tag-pattern": "^([\\d.]+-[\\d]+)$" @@ -294,8 +294,8 @@ "sources": [ { "type": "archive", - "url": "https://download.gnome.org/sources/vte/0.79/vte-0.79.91.tar.xz", - "sha256": "adca667d40ae1839ba258b63701cd05fba249303d72258711cc69294b2cb8646", + "url": "https://download.gnome.org/sources/vte/0.80/vte-0.80.0.tar.xz", + "sha256": "267f63739765e568cf8113d0e2ee8f593028946187854bebe268c778e62647c8", "x-checker-data": { "type": "gnome", "name": "vte", @@ -323,7 +323,7 @@ "is-important": true, "url": "https://api.github.com/repos/bottlesdevs/runtime/releases/latest", "version-query": ".tag_name", - "url-query": "https://github.com/bottlesdevs/runtime/releases/download/$version/runtime-$version.tar.gz" + "url-query": "\"https://github.com/bottlesdevs/runtime/releases/download/\" + $version + \"/runtime-\" + $version + \".tar.gz\"" } } ] @@ -342,52 +342,15 @@ "sources": [ { "type": "archive", - "url": "https://github.com/FluidSynth/fluidsynth/archive/v2.3.5.tar.gz", - "sha256": "f89e8e983ecfb4a5b4f5d8c2b9157ed18d15ed2e36246fa782f18abaea550e0d" - } - ] - }, - { - "name": "libsass", - "buildsystem": "meson", - "sources": [ - { - "type": "git", - "url": "https://github.com/lazka/libsass.git", - "commit": "aac79dccd3c8f7e8f22125f87a119f3b1ee9d487" - } - ] - }, - { - "name": "sassc", - "buildsystem": "meson", - "sources": [ - { - "type": "git", - "url": "https://github.com/lazka/sassc.git", - "commit": "a1950c2d95ea4c051feb90bb1f43559fbb54bf36" - } - ] - }, - { - "name": "libadwaita", - "buildsystem": "meson", - "config-opts": [ - "-Dexamples=false", - "-Dtests=false" - ], - "cleanup": [ - "/include", - "/lib/pkgconfig", - "/libexec", - "/share/dbus-1" - ], - "sources": [ - { - "type": "git", - "url": "https://gitlab.gnome.org/GNOME/libadwaita.git", - "tag": "1.7.beta", - "commit": "10dbadc7a770f36e20d5053e6b08676bc36f7957" + "url": "https://github.com/FluidSynth/fluidsynth/archive/v2.4.4.tar.gz", + "sha256": "fc492a255f453e65ac5b99a25e6ffbe0fbd64d6a4fe824bacd68de16fe8af7ba", + "x-checker-data": { + "type": "json", + "is-important": true, + "url": "https://api.github.com/repos/FluidSynth/fluidsynth/releases/latest", + "version-query": ".tag_name", + "url-query": "\"https://github.com/FluidSynth/fluidsynth/archive/\" + $version + \".tar.gz\"" + } } ] }, From 822bede074f546be8c0a3b05c4ce9ab32048c366 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Sat, 12 Apr 2025 01:04:46 -0400 Subject: [PATCH 091/146] flatpak: Split dependencies --- build-aux/bottles-deps.yaml | 181 +++++++++++++ build-aux/com.usebottles.bottles.Devel.json | 274 +------------------- 2 files changed, 182 insertions(+), 273 deletions(-) create mode 100644 build-aux/bottles-deps.yaml diff --git a/build-aux/bottles-deps.yaml b/build-aux/bottles-deps.yaml new file mode 100644 index 00000000000..5ca3531fdaa --- /dev/null +++ b/build-aux/bottles-deps.yaml @@ -0,0 +1,181 @@ +name: bottles-deps +modules: + - name: vmtouch + buildsystem: simple + sources: + - type: git + url: https://github.com/hoytech/vmtouch + commit: af86e27675843b3c7e4ddfee66ddbaf44eff43c4 + x-checker-data: + type: json + url: https://api.github.com/repos/hoytech/vmtouch/commits + commit-query: first( .[].sha ) + timestamp-query: first( .[].commit.committer.date ) + build-commands: + - make + - make install PREFIX=/app + - name: vulkan-tools + buildsystem: cmake-ninja + config-opts: + - -DGLSLANG_INSTALL_DIR=/app + - -DVULKAN_HEADERS_INSTALL_DIR=/app + - -DCMAKE_BUILD_TYPE=Release + sources: + - type: git + url: https://github.com/KhronosGroup/Vulkan-Tools.git + tag: vulkan-sdk-1.4.309.0 + commit: bf9fcd2d62ea9eac52e5351c02e35cb61ec5e873 + x-checker-data: + type: git + tag-pattern: ^vulkan-sdk-([\d.]+)$ + modules: + - name: volk + buildsystem: cmake-ninja + config-opts: + - -DVOLK_INSTALL=ON + sources: + - type: archive + url: https://github.com/zeux/volk/archive/refs/tags/1.4.304.tar.gz + sha256: ab3d4a8ccaeb32652259cdd008399504a41792675b0421d90b67729ee274746f + - name: vulkan-headers + buildsystem: cmake-ninja + sources: + - type: git + url: https://github.com/KhronosGroup/Vulkan-Headers.git + tag: vulkan-sdk-1.4.309.0 + commit: 952f776f6573aafbb62ea717d871cd1d6816c387 + x-checker-data: + type: git + tag-pattern: ^vulkan-sdk-([\d.]+)$ + - name: xdpyinfo + buildsystem: autotools + sources: + - type: git + url: https://gitlab.freedesktop.org/xorg/app/xdpyinfo.git + tag: xdpyinfo-1.3.4 + commit: ea4083ccb2a5ce4252acabeb2eb7bf49f7be25e0 + x-checker-data: + type: git + tag-pattern: ^xdpyinfo-([\d.]+)$ + - name: ImageMagick + buildsystem: autotools + config-opts: + - --disable-static + - --disable-docs + - --with-hdri + - --with-pic + sources: + - type: git + url: https://github.com/ImageMagick/ImageMagick + tag: 7.1.1-46 + commit: 8209e844cf02b5365918da83b2fc811442813080 + x-checker-data: + type: git + tag-pattern: ^([\d.]+-[\d]+)$ + - name: libportal + buildsystem: meson + config-opts: + - -Dbackend-gtk3=disabled + - -Dbackend-gtk4=enabled + - -Dportal-tests=false + - -Dvapi=false + - -Ddocs=false + sources: + - type: git + url: https://github.com/flatpak/libportal + tag: 0.9.1 + commit: 8f5dc8d192f6e31dafe69e35219e3b707bde71ce + x-checker-data: + type: git + is-important: true + tag-pattern: ^([\d.]+)$ + - name: blueprint-compiler + buildsystem: meson + sources: + - type: git + url: https://gitlab.gnome.org/jwestman/blueprint-compiler + tag: v0.16.0 + commit: 04ef0944db56ab01307a29aaa7303df6067cb3c0 + x-checker-data: + type: git + tag-pattern: ^v([\d.]+)$ + - name: vkbasalt-cli + buildsystem: simple + build-commands: + - python3 setup.py install --prefix=/app --root=/ + sources: + - type: git + url: https://gitlab.com/TheEvilSkeleton/vkbasalt-cli + tag: v3.1.1 + commit: bba740f77357cfa3558f02f6b8decd8f5a8eaf4e + x-checker-data: + type: git + is-important: true + tag-pattern: ^v([\d.]+)$ + - name: EasyTerm + buildsystem: simple + build-commands: + - python3 setup.py install --prefix=/app --root=/ + sources: + - type: git + url: https://github.com/bottlesdevs/EasyTerm + tag: 0.2.0 + commit: 6fbeab0470df55aeab141a45763147440b2f0290 + x-checker-data: + type: git + is-important: true + tag-pattern: ^([\d.]+)$ + modules: + - name: fast_float + buildsystem: cmake-ninja + sources: + - type: git + url: https://github.com/fastfloat/fast_float.git + tag: v8.0.2 + commit: 50a80a73ab2ab256ba1c3bf86923ddd8b4202bc7 + - name: vte + buildsystem: meson + config-opts: + - -Dvapi=false + sources: + - type: archive + url: https://download.gnome.org/sources/vte/0.80/vte-0.80.0.tar.xz + sha256: 267f63739765e568cf8113d0e2ee8f593028946187854bebe268c778e62647c8 + x-checker-data: + type: gnome + name: vte + stable-only: true + - name: runtime + buildsystem: simple + build-commands: + - mkdir -p /app/etc/runtime + - cp -a * /app/etc/runtime/ + sources: + - type: archive + url: https://github.com/bottlesdevs/runtime/releases/download/0.6.3/runtime-0.6.3.tar.gz + sha256: d7749b48927bd782e128e372a1d7085133fbe300eb9193134eb821f61bc5fad6 + x-checker-data: + type: json + is-important: true + url: https://api.github.com/repos/bottlesdevs/runtime/releases/latest + version-query: .tag_name + url-query: '"https://github.com/bottlesdevs/runtime/releases/download/" + $version + "/runtime-" + $version + ".tar.gz"' + - name: fluidsynth + buildsystem: cmake-ninja + cleanup: + - /bin + - /include + - /lib/cmake + - /lib/pkgconfig + - /share/man + - '*.so' + sources: + - type: archive + url: https://github.com/FluidSynth/fluidsynth/archive/v2.4.4.tar.gz + sha256: fc492a255f453e65ac5b99a25e6ffbe0fbd64d6a4fe824bacd68de16fe8af7ba + x-checker-data: + type: json + is-important: true + url: https://api.github.com/repos/FluidSynth/fluidsynth/releases/latest + version-query: .tag_name + url-query: '"https://github.com/FluidSynth/fluidsynth/archive/" + $version + ".tar.gz"' diff --git a/build-aux/com.usebottles.bottles.Devel.json b/build-aux/com.usebottles.bottles.Devel.json index 9d730fea0a1..3407c223e2e 100644 --- a/build-aux/com.usebottles.bottles.Devel.json +++ b/build-aux/com.usebottles.bottles.Devel.json @@ -81,279 +81,7 @@ ], "modules": [ "pypi-deps.yaml", - { - "name": "vmtouch", - "buildsystem": "simple", - "sources": [ - { - "type": "git", - "url": "https://github.com/hoytech/vmtouch", - "commit": "af86e27675843b3c7e4ddfee66ddbaf44eff43c4", - "x-checker-data": { - "type": "json", - "url": "https://api.github.com/repos/hoytech/vmtouch/commits", - "commit-query": "first( .[].sha )", - "timestamp-query": "first( .[].commit.committer.date )" - } - } - ], - "build-commands": [ - "make", - "make install PREFIX=/app" - ] - }, - { - "name": "vulkan-tools", - "buildsystem": "cmake-ninja", - "config-opts": [ - "-DGLSLANG_INSTALL_DIR=/app", - "-DVULKAN_HEADERS_INSTALL_DIR=/app", - "-DCMAKE_BUILD_TYPE=Release" - ], - "sources": [ - { - "type": "git", - "url": "https://github.com/KhronosGroup/Vulkan-Tools.git", - "tag": "vulkan-sdk-1.4.309.0", - "commit": "bf9fcd2d62ea9eac52e5351c02e35cb61ec5e873", - "x-checker-data": { - "type": "git", - "tag-pattern": "^vulkan-sdk-([\\d.]+)$" - } - } - ], - "modules": [ - { - "name": "volk", - "buildsystem": "cmake-ninja", - "config-opts": [ - "-DVOLK_INSTALL=ON" - ], - "sources": [ - { - "type": "archive", - "url": "https://github.com/zeux/volk/archive/refs/tags/1.4.304.tar.gz", - "sha256": "ab3d4a8ccaeb32652259cdd008399504a41792675b0421d90b67729ee274746f" - } - ] - }, - { - "name": "vulkan-headers", - "buildsystem": "cmake-ninja", - "sources": [ - { - "type": "git", - "url": "https://github.com/KhronosGroup/Vulkan-Headers.git", - "tag": "vulkan-sdk-1.4.309.0", - "commit": "952f776f6573aafbb62ea717d871cd1d6816c387", - "x-checker-data": { - "type": "git", - "tag-pattern": "^vulkan-sdk-([\\d.]+)$" - } - } - ] - } - ] - }, - { - "name": "xdpyinfo", - "buildsystem": "autotools", - "sources": [ - { - "type": "git", - "url": "https://gitlab.freedesktop.org/xorg/app/xdpyinfo.git", - "tag": "xdpyinfo-1.3.4", - "commit": "ea4083ccb2a5ce4252acabeb2eb7bf49f7be25e0", - "x-checker-data": { - "type": "git", - "tag-pattern": "^xdpyinfo-([\\d.]+)$" - } - } - ] - }, - { - "name": "ImageMagick", - "buildsystem": "autotools", - "config-opts": [ - "--disable-static", - "--disable-docs", - "--with-hdri", - "--with-pic" - ], - "sources": [ - { - "type": "git", - "url": "https://github.com/ImageMagick/ImageMagick", - "tag": "7.1.1-46", - "commit": "8209e844cf02b5365918da83b2fc811442813080", - "x-checker-data": { - "type": "git", - "tag-pattern": "^([\\d.]+-[\\d]+)$" - } - } - ] - }, - { - "name": "libportal", - "buildsystem": "meson", - "config-opts": [ - "-Dbackend-gtk3=disabled", - "-Dbackend-gtk4=enabled", - "-Dportal-tests=false", - "-Dvapi=false", - "-Ddocs=false" - ], - "sources": [ - { - "type": "git", - "url": "https://github.com/flatpak/libportal", - "tag": "0.9.1", - "commit": "8f5dc8d192f6e31dafe69e35219e3b707bde71ce", - "x-checker-data": { - "type": "git", - "is-important": true, - "tag-pattern": "^([\\d.]+)$" - } - } - ] - }, - { - "name": "blueprint-compiler", - "buildsystem": "meson", - "sources": [ - { - "type": "git", - "url": "https://gitlab.gnome.org/jwestman/blueprint-compiler", - "tag": "v0.16.0", - "commit": "04ef0944db56ab01307a29aaa7303df6067cb3c0", - "x-checker-data": { - "type": "git", - "tag-pattern": "^v([\\d.]+)$" - } - } - ] - }, - { - "name": "vkbasalt-cli", - "buildsystem": "simple", - "build-commands": [ - "python3 setup.py install --prefix=/app --root=/" - ], - "sources": [ - { - "type": "git", - "url": "https://gitlab.com/TheEvilSkeleton/vkbasalt-cli", - "tag": "v3.1.1", - "commit": "bba740f77357cfa3558f02f6b8decd8f5a8eaf4e", - "x-checker-data": { - "type": "git", - "is-important": true, - "tag-pattern": "^v([\\d.]+)$" - } - } - ] - }, - { - "name": "EasyTerm", - "buildsystem": "simple", - "build-commands": [ - "python3 setup.py install --prefix=/app --root=/" - ], - "sources": [ - { - "type": "git", - "url": "https://github.com/bottlesdevs/EasyTerm", - "tag": "0.2.0", - "commit": "6fbeab0470df55aeab141a45763147440b2f0290", - "x-checker-data": { - "type": "git", - "is-important": true, - "tag-pattern": "^([\\d.]+)$" - } - } - ], - "modules": [ - { - "name": "fast_float", - "buildsystem": "cmake-ninja", - "sources": [ - { - "type": "git", - "url": "https://github.com/fastfloat/fast_float.git", - "tag": "v8.0.2", - "commit": "50a80a73ab2ab256ba1c3bf86923ddd8b4202bc7" - } - ] - }, - { - "name": "vte", - "buildsystem": "meson", - "config-opts": [ - "-Dvapi=false" - ], - "sources": [ - { - "type": "archive", - "url": "https://download.gnome.org/sources/vte/0.80/vte-0.80.0.tar.xz", - "sha256": "267f63739765e568cf8113d0e2ee8f593028946187854bebe268c778e62647c8", - "x-checker-data": { - "type": "gnome", - "name": "vte", - "stable-only": true - } - } - ] - } - ] - }, - { - "name": "runtime", - "buildsystem": "simple", - "build-commands": [ - "mkdir -p /app/etc/runtime", - "cp -a * /app/etc/runtime/" - ], - "sources": [ - { - "type": "archive", - "url": "https://github.com/bottlesdevs/runtime/releases/download/0.6.3/runtime-0.6.3.tar.gz", - "sha256": "d7749b48927bd782e128e372a1d7085133fbe300eb9193134eb821f61bc5fad6", - "x-checker-data": { - "type": "json", - "is-important": true, - "url": "https://api.github.com/repos/bottlesdevs/runtime/releases/latest", - "version-query": ".tag_name", - "url-query": "\"https://github.com/bottlesdevs/runtime/releases/download/\" + $version + \"/runtime-\" + $version + \".tar.gz\"" - } - } - ] - }, - { - "name": "fluidsynth", - "buildsystem": "cmake-ninja", - "cleanup": [ - "/bin", - "/include", - "/lib/cmake", - "/lib/pkgconfig", - "/share/man", - "*.so" - ], - "sources": [ - { - "type": "archive", - "url": "https://github.com/FluidSynth/fluidsynth/archive/v2.4.4.tar.gz", - "sha256": "fc492a255f453e65ac5b99a25e6ffbe0fbd64d6a4fe824bacd68de16fe8af7ba", - "x-checker-data": { - "type": "json", - "is-important": true, - "url": "https://api.github.com/repos/FluidSynth/fluidsynth/releases/latest", - "version-query": ".tag_name", - "url-query": "\"https://github.com/FluidSynth/fluidsynth/archive/\" + $version + \".tar.gz\"" - } - } - ] - }, + "bottles-deps.yaml", { "name": "bottles", "builddir": true, From 6f4eb14f0cedd95b22b1ce56381eb6f512b23ccb Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Fri, 17 Jan 2025 19:03:28 -0500 Subject: [PATCH 092/146] backend: Remove connection checks --- bottles/backend/managers/component.py | 8 +- bottles/backend/managers/dependency.py | 7 +- bottles/backend/managers/installer.py | 7 +- bottles/backend/managers/manager.py | 78 ++----------- bottles/backend/managers/repository.py | 9 +- bottles/backend/utils/connection.py | 110 ------------------ bottles/backend/utils/meson.build | 1 - bottles/frontend/details_dependencies_view.py | 6 - bottles/frontend/preferences.py | 23 ++-- bottles/frontend/window.py | 24 +--- 10 files changed, 27 insertions(+), 246 deletions(-) delete mode 100644 bottles/backend/utils/connection.py diff --git a/bottles/backend/managers/component.py b/bottles/backend/managers/component.py index 9065f7f337f..ba4bfba239a 100644 --- a/bottles/backend/managers/component.py +++ b/bottles/backend/managers/component.py @@ -44,10 +44,9 @@ # noinspection PyTypeChecker class ComponentManager: - def __init__(self, manager, offline: bool = False): + def __init__(self, manager): self.__manager = manager - self.__repo = manager.repository_manager.get_repo("components", offline) - self.__utils_conn = manager.utils_conn + self.__repo = manager.repository_manager.get_repo("components") @lru_cache def get_component(self, name: str, plain: bool = False) -> dict: @@ -58,9 +57,6 @@ def fetch_catalog(self) -> dict: Fetch all components from the Bottles repository, mark the installed ones and return a dict with the catalog. """ - if not self.__utils_conn.check_connection(): - return {} - catalog = { "runtimes": {}, "wine": {}, diff --git a/bottles/backend/managers/dependency.py b/bottles/backend/managers/dependency.py index 0c95dfc8dbf..29084a02d64 100644 --- a/bottles/backend/managers/dependency.py +++ b/bottles/backend/managers/dependency.py @@ -43,10 +43,9 @@ class DependencyManager: - def __init__(self, manager, offline: bool = False): + def __init__(self, manager): self.__manager = manager - self.__repo = manager.repository_manager.get_repo("dependencies", offline) - self.__utils_conn = manager.utils_conn + self.__repo = manager.repository_manager.get_repo("dependencies") @lru_cache def get_dependency(self, name: str, plain: bool = False) -> str | dict | bool: @@ -59,8 +58,6 @@ def fetch_catalog(self) -> dict: and return these as a dictionary. It also returns an empty dictionary if there are no dependencies or fails to fetch them. """ - if not self.__utils_conn.check_connection(): - return {} catalog = {} index = self.__repo.catalog diff --git a/bottles/backend/managers/installer.py b/bottles/backend/managers/installer.py index 5bf63a53786..bee8140797a 100644 --- a/bottles/backend/managers/installer.py +++ b/bottles/backend/managers/installer.py @@ -36,10 +36,9 @@ class InstallerManager: - def __init__(self, manager, offline: bool = False): + def __init__(self, manager): self.__manager = manager - self.__repo = manager.repository_manager.get_repo("installers", offline) - self.__utils_conn = manager.utils_conn + self.__repo = manager.repository_manager.get_repo("installers") self.__component_manager = manager.component_manager self.__local_resources = {} @@ -68,8 +67,6 @@ def fetch_catalog(self) -> dict: """Fetch the installers catalog from the repository""" catalog = {} index = self.__repo.catalog - if not self.__utils_conn.check_connection(): - return {} for installer in index.items(): catalog[installer[0]] = installer[1] diff --git a/bottles/backend/managers/manager.py b/bottles/backend/managers/manager.py index c3d990c4722..40f9200f80b 100644 --- a/bottles/backend/managers/manager.py +++ b/bottles/backend/managers/manager.py @@ -53,7 +53,6 @@ from bottles.backend.models.samples import Samples from bottles.backend.state import SignalManager, Signals, Events, EventManager from bottles.backend.utils import yaml -from bottles.backend.utils.connection import ConnectionUtils from bottles.backend.utils.file import FileUtils from bottles.backend.utils.generic import sort_by_version from bottles.backend.utils.gpu import GPUUtils @@ -106,7 +105,6 @@ class Manager(metaclass=Singleton): def __init__( self, g_settings: Any = None, - check_connection: bool = True, is_cli: bool = False, **kwargs, ): @@ -117,14 +115,8 @@ def __init__( # common variables self.is_cli = is_cli self.settings = g_settings or GSettingsStub - self.utils_conn = ConnectionUtils( - force_offline=self.is_cli or self.settings.get_boolean("force-offline") - ) self.data_mgr = DataManager() - _offline = True - - if check_connection: - _offline = not self.utils_conn.check_connection() + _offline = False # validating user-defined Paths.bottles if user_bottles_path := self.data_mgr.get(UserDataKeys.CustomBottlesPath): @@ -137,17 +129,14 @@ def __init__( ) # sub-managers - self.repository_manager = RepositoryManager(get_index=not _offline) - if self.repository_manager.aborted_connections > 0: - self.utils_conn.status = False - _offline = True + self.repository_manager = RepositoryManager() times["RepositoryManager"] = time.time() self.versioning_manager = VersioningManager(self) times["VersioningManager"] = time.time() - self.component_manager = ComponentManager(self, _offline) - self.installer_manager = InstallerManager(self, _offline) - self.dependency_manager = DependencyManager(self, _offline) + self.component_manager = ComponentManager(self) + self.installer_manager = InstallerManager(self) + self.dependency_manager = DependencyManager(self) self.import_manager = ImportManager(self) times["ImportManager"] = time.time() self.steam_manager = SteamManager() @@ -420,25 +409,7 @@ def check_runners(self, install_latest: bool = True) -> bool: if len(tmp_runners) == 0 and install_latest: logging.warning("No managed runners found.") - - if self.utils_conn.check_connection(): - # if connected, install the latest runner from repository - try: - if not self.settings.get_boolean("release-candidate"): - tmp_runners = [] - for runner in self.supported_wine_runners.items(): - if runner[1]["Channel"] not in ["rc", "unstable"]: - tmp_runners.append(runner) - break - runner_name = next(iter(tmp_runners))[0] - else: - tmp_runners = self.supported_wine_runners - runner_name = next(iter(tmp_runners)) - self.component_manager.install("runner", runner_name) - except StopIteration: - return False - else: - return False + return False return True @@ -451,13 +422,6 @@ def check_runtimes(self, install_latest: bool = True) -> bool: runtimes = os.listdir(Paths.runtimes) if len(runtimes) == 0: - if install_latest and self.utils_conn.check_connection(): - logging.warning("No runtime found.") - try: - version = next(iter(self.supported_runtimes)) - return self.component_manager.install("runtime", version) - except StopIteration: - return False return False runtime = runtimes[0] # runtimes cannot be more than one @@ -480,15 +444,6 @@ def check_winebridge( winebridge = os.listdir(Paths.winebridge) if len(winebridge) == 0 or update: - if install_latest and self.utils_conn.check_connection(): - logging.warning("No WineBridge found.") - try: - version = next(iter(self.supported_winebridge)) - self.component_manager.install("winebridge", version) - self.winebridge_available = [version] - return True - except StopIteration: - return False return False version_file = os.path.join(Paths.winebridge, "VERSION") @@ -637,26 +592,7 @@ def __check_component( if len(component["available"]) == 0 and install_latest: logging.warning(f"No {component_type} found.") - - if self.utils_conn.check_connection(): - # if connected, install the latest component from repository - try: - if not self.settings.get_boolean("release-candidate"): - tmp_components = [] - for cpnt in component["supported"].items(): - if cpnt[1]["Channel"] not in ["rc", "unstable"]: - tmp_components.append(cpnt) - break - component_version = next(iter(tmp_components))[0] - else: - tmp_components = component["supported"] - component_version = next(iter(tmp_components)) - self.component_manager.install(component_type, component_version) - component["available"] = [component_version] - except StopIteration: - return False - else: - return False + return False try: return sort_by_version(component["available"]) diff --git a/bottles/backend/managers/repository.py b/bottles/backend/managers/repository.py index 78da3401f7d..41401ccb11d 100644 --- a/bottles/backend/managers/repository.py +++ b/bottles/backend/managers/repository.py @@ -50,19 +50,18 @@ class RepositoryManager: }, } - def __init__(self, get_index=True): + def __init__(self): self.do_get_index = True self.aborted_connections = 0 SignalManager.connect(Signals.ForceStopNetworking, self.__stop_index) self.__check_personals() - if get_index: - self.__get_index() + self.__get_index() - def get_repo(self, name: str, offline: bool = False): + def get_repo(self, name: str): if name in self.__repositories: repo = self.__repositories[name] - return repo["cls"](repo["url"], repo["index"], offline=offline) + return repo["cls"](repo["url"], repo["index"]) logging.error(f"Repository {name} not found") diff --git a/bottles/backend/utils/connection.py b/bottles/backend/utils/connection.py deleted file mode 100644 index acc84a33636..00000000000 --- a/bottles/backend/utils/connection.py +++ /dev/null @@ -1,110 +0,0 @@ -# connection.py -# -# Copyright 2022 brombinmirko -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, in version 3 of the License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# - -import os -from datetime import datetime -from gettext import gettext as _ - -import pycurl - -from bottles.backend.logger import Logger -from bottles.backend.models.result import Result -from bottles.backend.state import SignalManager, Signals, Notification - -logging = Logger() - - -class ConnectionUtils: - """ - This class is used to check the connection, pinging the official - Bottle's website. If the connection is offline, the user will be - notified and False will be returned, otherwise True. - """ - - _status: bool | None = None - last_check = None - - def __init__(self, force_offline=False, **kwargs): - super().__init__(**kwargs) - self.force_offline = force_offline - self.do_check_connection = True - self.aborted_connections = 0 - SignalManager.connect(Signals.ForceStopNetworking, self.stop_check) - - @property - def status(self) -> bool | None: - return self._status - - @status.setter - def status(self, value: bool): - if value is None: - logging.error("Cannot set network status to None") - return - self._status = value - SignalManager.send(Signals.NetworkStatusChanged, Result(status=self.status)) - - def __curl_progress(self, _download_t, _download_d, _upload_t, _upload_d): - if self.do_check_connection: - return pycurl.E_OK - else: - self.aborted_connections += 1 - return pycurl.E_ABORTED_BY_CALLBACK - - def stop_check(self, res: Result): - if res.status: - self.do_check_connection = False - - def check_connection(self, show_notification=False) -> bool | None: - """check network status, send result through signal NetworkReady and return""" - if self.force_offline or "FORCE_OFFLINE" in os.environ: - logging.info("Forcing offline mode") - self.status = False - return False - - try: - c = pycurl.Curl() - c.setopt(c.URL, "https://ping.usebottles.com") - c.setopt(c.FOLLOWLOCATION, True) - c.setopt(c.NOBODY, True) - c.setopt(c.NOPROGRESS, False) - c.setopt(c.XFERINFOFUNCTION, self.__curl_progress) - c.perform() - - if c.getinfo(pycurl.HTTP_CODE) != 200: - raise Exception("Connection status: offline …") - - self.last_check = datetime.now() - self.status = True - except Exception: - logging.warning("Connection status: offline …") - if show_notification: - SignalManager.send( - Signals.GNotification, - Result( - True, - Notification( - title="Bottles", - text=_("You are offline, unable to download."), - image="network-wireless-disabled-symbolic", - ), - ), - ) - self.last_check = datetime.now() - self.status = False - finally: - self.do_check_connection = True - return self.status diff --git a/bottles/backend/utils/meson.build b/bottles/backend/utils/meson.build index ab74896ff1b..dc0a08b3b67 100644 --- a/bottles/backend/utils/meson.build +++ b/bottles/backend/utils/meson.build @@ -22,7 +22,6 @@ bottles_sources = [ 'yaml.py', 'nvidia.py', 'threading.py', - 'connection.py', 'gsettings_stub.py', 'json.py', 'singleton.py' diff --git a/bottles/frontend/details_dependencies_view.py b/bottles/frontend/details_dependencies_view.py index 41cc42ce427..30e8412c4d8 100644 --- a/bottles/frontend/details_dependencies_view.py +++ b/bottles/frontend/details_dependencies_view.py @@ -64,9 +64,6 @@ def __init__(self, details, config: BottleConfig, **kwargs): ) self.btn_help.connect("clicked", open_doc_url, "bottles/dependencies") - if not self.manager.utils_conn.status: - self.stack.set_visible_child_name("page_offline") - self.spinner_loading.start() def __search_dependencies(self, *_args): @@ -100,9 +97,6 @@ def update(self, _widget=False, config: BottleConfig | None = None): self.config = config # Not sure if it's the best place to make this check - if not self.manager.utils_conn.status: - return - self.stack.set_visible_child_name("page_loading") def new_dependency(dependency, plain=False): diff --git a/bottles/frontend/preferences.py b/bottles/frontend/preferences.py index 3fe92492773..f58a056e2e5 100644 --- a/bottles/frontend/preferences.py +++ b/bottles/frontend/preferences.py @@ -163,10 +163,6 @@ def __init__(self, window, **kwargs): self.dlls_stack.set_visible_child_name("dlls_loading") self.dlls_spinner.start() - if not self.manager.utils_conn.status: - self.installers_stack.set_visible_child_name("installers_offline") - self.dlls_stack.set_visible_child_name("dlls_offline") - RunAsync(self.ui_update) # connect signals @@ -195,16 +191,15 @@ def empty_list(self): self.__registry = [] def ui_update(self): - if self.manager.utils_conn.status: - EventManager.wait(Events.ComponentsOrganizing) - GLib.idle_add(self.empty_list) - GLib.idle_add(self.populate_runners_list) - GLib.idle_add(self.populate_dxvk_list) - GLib.idle_add(self.populate_vkd3d_list) - GLib.idle_add(self.populate_nvapi_list) - GLib.idle_add(self.populate_latencyflex_list) - - GLib.idle_add(self.dlls_stack.set_visible_child_name, "dlls_list") + EventManager.wait(Events.ComponentsOrganizing) + GLib.idle_add(self.empty_list) + GLib.idle_add(self.populate_runners_list) + GLib.idle_add(self.populate_dxvk_list) + GLib.idle_add(self.populate_vkd3d_list) + GLib.idle_add(self.populate_nvapi_list) + GLib.idle_add(self.populate_latencyflex_list) + + GLib.idle_add(self.dlls_stack.set_visible_child_name, "dlls_list") def __toggle_night(self, widget, state): if self.settings.get_boolean("dark-theme"): diff --git a/bottles/frontend/window.py b/bottles/frontend/window.py index c627e8de9b2..c74b05beab5 100644 --- a/bottles/frontend/window.py +++ b/bottles/frontend/window.py @@ -30,7 +30,6 @@ from bottles.backend.models.config import BottleConfig from bottles.backend.models.result import Result from bottles.backend.state import SignalManager, Signals, Notification -from bottles.backend.utils.connection import ConnectionUtils from bottles.backend.utils.threading import RunAsync from bottles.frontend.operation import TaskSyncer from bottles.frontend.params import APP_ID, BASE_ID, PROFILE @@ -78,9 +77,6 @@ def __init__(self, arg_bottle, **kwargs): super().__init__(**kwargs, default_width=width, default_height=height) - self.utils_conn = ConnectionUtils( - force_offline=self.settings.get_boolean("force-offline") - ) self.manager = None self.arg_bottle = arg_bottle self.app = kwargs.get("application") @@ -141,7 +137,6 @@ def response(dialog, response, *args): "https://usebottles.com/funding/", ) self.btn_add.connect("clicked", self.show_add_view) - self.btn_noconnection.connect("clicked", self.check_for_connection) self.stack_main.connect("notify::visible-child", self.__on_page_changed) # backend signal handlers @@ -192,15 +187,6 @@ def title(self, title, subtitle: str = ""): self.view_switcher_title.set_title(title) self.view_switcher_title.set_subtitle(subtitle) - def check_for_connection(self, status): - """ - This method checks if the client has an internet connection. - If true, the manager checks will be performed, unlocking all the - features locked for no internet connection. - """ - if self.utils_conn.check_connection(): - self.manager.checks(install_latest=False, first_run=True) - def __on_start(self): """ This method is called before the window is shown. This check if there @@ -278,16 +264,8 @@ def set_manager(result: Manager, error=None): dialog.present() def get_manager(): - if self.utils_conn.check_connection(): - SignalManager.connect( - Signals.RepositoryFetched, self.page_loading.add_fetched - ) - # do not redo connection if aborted connection - mng = Manager( - g_settings=self.settings, - check_connection=self.utils_conn.aborted_connections == 0, - ) + mng = Manager(g_settings=self.settings) return mng self.show_loading_view() From 03c58427a2b321d78bc983eb78e19b0b49469794 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Mon, 20 Jan 2025 11:56:16 -0500 Subject: [PATCH 093/146] frontend: Remove arg_bottle attribute --- bottles/frontend/bottles_list_view.py | 3 +-- bottles/frontend/main.py | 2 +- bottles/frontend/window.py | 5 ++--- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/bottles/frontend/bottles_list_view.py b/bottles/frontend/bottles_list_view.py index e2cffa18c25..5c5d04d3a5c 100644 --- a/bottles/frontend/bottles_list_view.py +++ b/bottles/frontend/bottles_list_view.py @@ -142,12 +142,11 @@ class BottlesListView(Adw.Bin): # endregion - def __init__(self, window, arg_bottle=None, **kwargs): + def __init__(self, window, **kwargs): super().__init__(**kwargs) # common variables and references self.window = window - self.arg_bottle = arg_bottle # connect signals self.btn_create.connect("clicked", self.window.show_add_view) diff --git a/bottles/frontend/main.py b/bottles/frontend/main.py index 35855da8726..54e5cb26d98 100644 --- a/bottles/frontend/main.py +++ b/bottles/frontend/main.py @@ -254,7 +254,7 @@ def do_activate(self): Adw.Application.do_activate(self) win = self.props.active_window if not win: - win = BottlesWindow(application=self, arg_bottle=self.arg_bottle) + win = BottlesWindow(application=self) self.win = win win.present() diff --git a/bottles/frontend/window.py b/bottles/frontend/window.py index c74b05beab5..fe82e7c6c8c 100644 --- a/bottles/frontend/window.py +++ b/bottles/frontend/window.py @@ -71,14 +71,13 @@ class BottlesWindow(Adw.ApplicationWindow): settings = Gio.Settings.new(BASE_ID) argument_executed = False - def __init__(self, arg_bottle, **kwargs): + def __init__(self, **kwargs): width = self.settings.get_int("window-width") height = self.settings.get_int("window-height") super().__init__(**kwargs, default_width=width, default_height=height) self.manager = None - self.arg_bottle = arg_bottle self.app = kwargs.get("application") self.set_icon_name(APP_ID) @@ -206,7 +205,7 @@ def set_manager(result: Manager, error=None): # Pages self.page_details = BottleDetailsView(self) - self.page_list = BottlesListView(self, arg_bottle=self.arg_bottle) + self.page_list = BottlesListView(self) self.page_importer = ImporterView(self) self.page_library = LibraryView(self) From d23fc4c42b359316b233ec401028cc4f6dddd0c1 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Mon, 20 Jan 2025 22:25:17 -0500 Subject: [PATCH 094/146] frontend: Remove CLI --- bottles/backend/managers/manager.py | 8 +- bottles/frontend/bottle_picker_dialog.py | 2 +- bottles/frontend/cli.py | 759 ------------------ bottles/frontend/meson.build | 9 - bottles/tests/backend/manager/test_manager.py | 8 +- 5 files changed, 5 insertions(+), 781 deletions(-) delete mode 100644 bottles/frontend/cli.py diff --git a/bottles/backend/managers/manager.py b/bottles/backend/managers/manager.py index 40f9200f80b..2c9d72ce6eb 100644 --- a/bottles/backend/managers/manager.py +++ b/bottles/backend/managers/manager.py @@ -105,7 +105,6 @@ class Manager(metaclass=Singleton): def __init__( self, g_settings: Any = None, - is_cli: bool = False, **kwargs, ): super().__init__(**kwargs) @@ -113,7 +112,6 @@ def __init__( times = {"start": time.time()} # common variables - self.is_cli = is_cli self.settings = g_settings or GSettingsStub self.data_mgr = DataManager() _offline = False @@ -142,10 +140,7 @@ def __init__( self.steam_manager = SteamManager() times["SteamManager"] = time.time() - if not self.is_cli: - times.update(self.checks(install_latest=False, first_run=True).data) - else: - logging.set_silent() + times.update(self.checks(install_latest=False, first_run=True).data) if "BOOT_TIME" in os.environ: _temp_times = times.copy() @@ -894,7 +889,6 @@ def process_bottle(bottle): if ( self.settings.get_boolean("steam-proton-support") and self.steam_manager.is_steam_supported - and not self.is_cli ): self.steam_manager.update_bottles() self.local_bottles.update(self.steam_manager.list_prefixes()) diff --git a/bottles/frontend/bottle_picker_dialog.py b/bottles/frontend/bottle_picker_dialog.py index 9332fc9327a..561040b3c8d 100644 --- a/bottles/frontend/bottle_picker_dialog.py +++ b/bottles/frontend/bottle_picker_dialog.py @@ -50,7 +50,7 @@ class BottlePickerDialog(Adw.ApplicationWindow): def __init__(self, arg_exe, **kwargs): super().__init__(**kwargs) self.arg_exe = arg_exe - mng = Manager(g_settings=self.settings, is_cli=True) + mng = Manager(g_settings=self.settings) mng.check_bottles() bottles = mng.local_bottles diff --git a/bottles/frontend/cli.py b/bottles/frontend/cli.py deleted file mode 100644 index 4008ec9e3a6..00000000000 --- a/bottles/frontend/cli.py +++ /dev/null @@ -1,759 +0,0 @@ -#!@PYTHON@ - -# cli.in -# -# Copyright 2020 brombinmirko -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - - -import argparse -import os -import signal -import sys -import uuid -import warnings - -import gi - -warnings.filterwarnings("ignore") # suppress GTK warnings -gi.require_version("Gtk", "4.0") - -APP_VERSION = "@APP_VERSION@" -pkgdatadir = "@pkgdatadir@" -# noinspection DuplicatedCode -gresource_path = f"{pkgdatadir}/bottles.gresource" -sys.path.insert(1, pkgdatadir) - -signal.signal(signal.SIGINT, signal.SIG_DFL) - -# ruff: noqa: E402 -from gi.repository import Gio - -from bottles.frontend.params import APP_ID -from bottles.backend.globals import Paths -from bottles.backend.health import HealthChecker -from bottles.backend.managers.manager import Manager -from bottles.backend.models.config import BottleConfig -from bottles.backend.wine.cmd import CMD -from bottles.backend.wine.control import Control -from bottles.backend.wine.executor import WineExecutor -from bottles.backend.wine.winecommand import WineCommand -from bottles.backend.wine.reg import Reg -from bottles.backend.wine.winepath import WinePath -from bottles.backend.wine.regedit import Regedit -from bottles.backend.wine.taskmgr import Taskmgr -from bottles.backend.wine.uninstaller import Uninstaller -from bottles.backend.wine.winecfg import WineCfg -from bottles.backend.wine.explorer import Explorer -from bottles.backend.wine.regkeys import RegKeys -from bottles.backend.runner import Runner -from bottles.backend.utils import json -from bottles.backend.utils.manager import ManagerUtils - - -# noinspection DuplicatedCode -class CLI: - settings = Gio.Settings.new(APP_ID) - - def __init__(self): - # self.__clear() - - self.parser = argparse.ArgumentParser( - description="Bottles is a tool to manage your bottles" - ) - self.parser.add_argument( - "-v", "--version", action="version", version=f"Bottles {APP_VERSION}" - ) - self.parser.add_argument( - "-j", "--json", action="store_true", help="Outputs in JSON format" - ) - - subparsers = self.parser.add_subparsers(dest="command", help="sub-command help") - - info_parser = subparsers.add_parser( - "info", help="Show information about Bottles" - ) - info_parser.add_argument( - "type", choices=["bottles-path", "health-check"], help="Type of information" - ) - - list_parser = subparsers.add_parser("list", help="List entities") - list_parser.add_argument( - "type", choices=["bottles", "components"], help="Type of entity" - ) - list_parser.add_argument( - "-f", - "--filter", - help="Filter bottles and components (e.g. '-f 'environment:gaming')", - ) - - programs_parser = subparsers.add_parser("programs", help="List programs") - programs_parser.add_argument( - "-b", "--bottle", help="Bottle name", required=True - ) - - add_parser = subparsers.add_parser("add", help="Add program") - add_parser.add_argument("-b", "--bottle", help="Bottle name", required=True) - add_parser.add_argument("-n", "--name", help="Program name", required=True) - add_parser.add_argument("-p", "--path", help="Program path", required=True) - add_parser.add_argument("-l", "--launch-options", help="Program launch options") - add_parser.add_argument( - "--no-dxvk", action="store_true", help="Disable DXVK for the program" - ) - add_parser.add_argument( - "--no-vkd3d", action="store_true", help="Disable VKD3D for the program" - ) - add_parser.add_argument( - "--no-dxvk-nvapi", - action="store_true", - help="Disable DXVK Nvapi for the program", - ) - - tools_parser = subparsers.add_parser("tools", help="Launch Wine tools") - tools_parser.add_argument( - "tool", - choices=[ - "cmd", - "winecfg", - "uninstaller", - "regedit", - "taskmgr", - "control", - "explorer", - ], - help="Tool to launch", - ) - tools_parser.add_argument("-b", "--bottle", help="Bottle name", required=True) - - reg_parser = subparsers.add_parser("reg", help="Manage registry") - reg_parser.add_argument( - "action", choices=["add", "edit", "del"], help="Action to perform" - ) - reg_parser.add_argument("-b", "--bottle", help="Bottle name", required=True) - reg_parser.add_argument("-k", "--key", help="Registry key", required=True) - reg_parser.add_argument("-v", "--value", help="Registry value", required=True) - reg_parser.add_argument("-d", "--data", help="Data to be set") - reg_parser.add_argument( - "-t", - "--key-type", - help="Data type", - choices=["REG_DWORD", "REG_SZ", "REG_BINARY", "REG_MULTI_SZ"], - ) - - edit_parser = subparsers.add_parser("edit", help="Edit a bottle configuration") - edit_parser.add_argument("-b", "--bottle", help="Bottle name", required=True) - edit_parser.add_argument( - "--params", help="Set parameters (e.g. '-p dxvk:true')" - ) - edit_parser.add_argument( - "--env-var", - help="Add new environment variable (e.g. '-env-var WINEDEBUG=-all')", - ) - edit_parser.add_argument( - "--win", help="Change Windows version (e.g. '--win win7')" - ) - edit_parser.add_argument( - "--runner", help="Change Runner (e.g. '--runner caffe-7.2')" - ) - edit_parser.add_argument( - "--dxvk", help="Change DXVK (e.g. '--dxvk dxvk-1.9.0')" - ) - edit_parser.add_argument( - "--vkd3d", help="Change VKD3D (e.g. '--vkd3d vkd3d-proton-2.6')" - ) - edit_parser.add_argument( - "--nvapi", help="Change DXVK-Nvapi (e.g. '--nvapi dxvk-nvapi-1.9.0')" - ) - edit_parser.add_argument( - "--latencyflex", - help="Change LatencyFleX (e.g. '--latencyflex latencyflex-v0.1.0')", - ) - - new_parser = subparsers.add_parser("new", help="Create a new bottle") - new_parser.add_argument("--bottle-name", help="Bottle name", required=True) - new_parser.add_argument( - "--environment", - help="Environment to apply (gaming|application|custom)", - required=True, - ) - new_parser.add_argument( - "--custom-environment", help="Path to a custom environment.yml file" - ) - new_parser.add_argument("--arch", help="Architecture (win32|win64)") - new_parser.add_argument("--runner", help="Name of the runner to be used") - new_parser.add_argument("--dxvk", help="Name of the dxvk to be used") - new_parser.add_argument("--vkd3d", help="Name of the vkd3d to be used") - new_parser.add_argument("--nvapi", help="Name of the dxvk-nvapi to be used") - new_parser.add_argument( - "--latencyflex", help="Name of the latencyflex to be used" - ) - - run_parser = subparsers.add_parser("run", help="Run a program") - run_parser.add_argument("-b", "--bottle", help="Bottle name", required=True) - run_parser.add_argument("-e", "--executable", help="Path to the executable") - run_parser.add_argument("-p", "--program", help="Program to run") - run_parser.add_argument( - "--args-replace", - action="store_false", - dest="keep_args", - help="Replace current program arguments, instead of append", - ) - run_parser.add_argument( - "args", - nargs="*", - action="extend", - help="Arguments to pass to the executable", - ) - - standalone_parser = subparsers.add_parser( - "standalone", - help="Generate a standalone script to launch commands " - "without passing trough Bottles", - ) - standalone_parser.add_argument( - "-b", "--bottle", help="Bottle name", required=True - ) - - shell_parser = subparsers.add_parser( - "shell", help="Launch commands in a Wine shell" - ) - shell_parser.add_argument("-b", "--bottle", help="Bottle name", required=True) - shell_parser.add_argument( - "-i", "--input", help="Command to execute", required=True - ) - - self.__process_args() - - @staticmethod - def __clear(): - os.system("clear") - - def __process_args(self): - self.args = self.parser.parse_args() - - # INFO parser - if self.args.command == "info": - self.show_info() - - # LIST parser - elif self.args.command == "list": - _filter = None if self.args.filter is None else self.args.filter - _type = self.args.type - - if _type == "bottles": - self.list_bottles(c_filter=_filter) - elif _type == "components": - self.list_components(c_filter=_filter) - - # PROGRAMS parser - elif self.args.command == "programs": - self.list_programs() - - # TOOLS parser - elif self.args.command == "tools": - self.launch_tool() - - # ADD parser - elif self.args.command == "add": - self.add_program() - - # REG parser - elif self.args.command == "reg": - self.manage_reg() - - # EDIT parser - elif self.args.command == "edit": - self.edit_bottle() - - # NEW parser - elif self.args.command == "new": - self.new_bottle() - - # RUN parser - elif self.args.command == "run": - self.run_program() - - # SHELL parser - elif self.args.command == "shell": - self.run_shell() - - # STANDALONE parser - elif self.args.command == "standalone": - self.generate_standalone() - - else: - self.parser.print_help() - - # region INFO - def show_info(self): - _type = self.args.type - if _type == "bottles-path": - res = Paths.bottles - sys.stdout.write(res) - exit(0) - elif _type == "health-check": - hc = HealthChecker() - if self.args.json: - sys.stdout.write(json.dumps(hc.get_results()) + "\n") - exit(0) - sys.stdout.write(hc.get_results(plain=True)) - - # endregion - - # region LIST - def list_bottles(self, c_filter=None): - mng = Manager(g_settings=self.settings, is_cli=True) - mng.check_bottles() - bottles = mng.local_bottles - - if c_filter and c_filter.startswith("environment:"): - environment = c_filter.split(":")[1].lower() - bottles = [ - name - for name, bottle in bottles.items() - if bottle.Environment.lower() == environment - ] - - if self.args.json: - sys.stdout.write(json.dumps(bottles)) - exit(0) - - if len(bottles) > 0: - sys.stdout.write(f"Found {len(bottles)} bottles:\n") - for b in bottles: - sys.stdout.write(f"- {b}\n") - - def list_components(self, c_filter=None): - mng = Manager(g_settings=self.settings, is_cli=True) - mng.check_runners(False) - mng.check_dxvk(False) - mng.check_vkd3d(False) - mng.check_nvapi(False) - mng.check_latencyflex(False) - - components = { - "runners": mng.runners_available, - "dxvk": mng.dxvk_available, - "vkd3d": mng.vkd3d_available, - "nvapi": mng.nvapi_available, - "latencyflex": mng.latencyflex_available, - } - - if c_filter and c_filter.startswith("category:"): - category = c_filter.split(":")[1].lower() - if category in components: - components = {category: components[category]} - - if self.args.json: - sys.stdout.write(json.dumps(components)) - exit(0) - - for c in components: - sys.stdout.write(f"Found {len(components[c])} {c}\n") - for i in components[c]: - sys.stdout.write(f"- {i}\n") - - # endregion - - # region PROGRAMS - def list_programs(self): - mng = Manager(g_settings=self.settings, is_cli=True) - mng.check_bottles() - _bottle = self.args.bottle - - if _bottle not in mng.local_bottles: - sys.stderr.write(f"Bottle {_bottle} not found\n") - exit(1) - - bottle = mng.local_bottles[_bottle] - programs = mng.get_programs(bottle) - programs = [p for p in programs if not p.get("removed", False)] - - if self.args.json: - sys.stdout.write(json.dumps(programs)) - exit(0) - - if len(programs) > 0: - sys.stdout.write(f"Found {len(programs)} programs:\n") - for p in programs: - sys.stdout.write(f"- {p['name']}\n") - - # endregion - - # region TOOLS - def launch_tool(self): - _bottle = self.args.bottle - _tool = self.args.tool - mng = Manager(g_settings=self.settings, is_cli=True) - mng.check_bottles() - - if _bottle not in mng.local_bottles: - sys.stderr.write(f"Bottle {_bottle} not found\n") - exit(1) - - bottle = mng.local_bottles[_bottle] - - if _tool == "cmd": - CMD(bottle).launch() - elif _tool == "winecfg": - WineCfg(bottle).launch() - elif _tool == "uninstaller": - Uninstaller(bottle).launch() - elif _tool == "regedit": - Regedit(bottle).launch() - elif _tool == "taskmgr": - Taskmgr(bottle).launch() - elif _tool == "control": - Control(bottle).launch() - elif _tool == "explorer": - Explorer(bottle).launch() - - # endregion - - # region ADD - def add_program(self): - _bottle = self.args.bottle - _name = self.args.name - _path = self.args.path - _launch_options = self.args.launch_options - _no_dxvk = self.args.no_dxvk - _no_vkd3d = self.args.no_vkd3d - _no_dxvk_nvapi = self.args.no_dxvk_nvapi - _executable = "" - _folder = "" - _uuid = str(uuid.uuid4()) - mng = Manager(g_settings=self.settings, is_cli=True) - mng.check_bottles() - - if _bottle not in mng.local_bottles: - sys.stderr.write(f"Bottle {_bottle} not found\n") - exit(1) - - bottle = mng.local_bottles[_bottle] - winepath = WinePath(bottle) - - if winepath.is_unix(_path): - if not os.path.exists(_path): - sys.stderr.write(f"Path doesn't exists or is unreachable: {_path}") - exit(1) - _executable = os.path.basename(_path) - _folder = os.path.dirname(_path) - elif winepath.is_windows(_path): - _executable = _path.split("\\")[-1] - _folder = ManagerUtils.get_exe_parent_dir(bottle, _path) - else: - sys.stderr.write(f"Unsupported path type: {_path}") - exit(1) - - _program = { - "arguments": _launch_options if _launch_options else "", - "executable": _executable, - "name": _name, - "folder": _folder, - "icon": "", - "id": _uuid, - "path": _path, - "dxvk": not _no_dxvk if _no_dxvk else bottle.Parameters.dxvk, - "vkd3d": not _no_vkd3d if _no_vkd3d else bottle.Parameters.vkd3d, - "dxvk_nvapi": ( - not _no_dxvk_nvapi if _no_dxvk_nvapi else bottle.Parameters.dxvk_nvapi - ), - } - mng.update_config(bottle, _uuid, _program, scope="External_Programs") - sys.stdout.write(f"'{_name}' added to '{bottle.Name}'!") - - # endregion - - # region REG - def manage_reg(self): - _bottle = self.args.bottle - _action = self.args.action - _key = self.args.key - _value = self.args.value - _data = self.args.data - _key_type = self.args.key_type - mng = Manager(g_settings=self.settings, is_cli=True) - mng.check_bottles() - - if _bottle not in mng.local_bottles: - sys.stderr.write(f"Bottle {_bottle} not found\n") - exit(1) - - bottle = mng.local_bottles[_bottle] - allowed_types = ["REG_SZ", "REG_DWORD", "REG_BINARY", "REG_MULTI_SZ"] - _key_type = "REG_SZ" if _key_type is None else _key_type.upper() - - if _action in ["add", "edit"]: - if _data is None or _key_type not in allowed_types: - sys.stderr.write("Missing or invalid data or key type\n") - exit(1) - Reg(bottle).add(_key, _value, _data, _key_type) - elif _action == "del": - Reg(bottle).remove(_key, _value) - - # endregion - - # region EDIT - def edit_bottle(self): - _bottle = self.args.bottle - _params = self.args.params - _env_var = self.args.env_var - _win = self.args.win - _runner = self.args.runner - _dxvk = self.args.dxvk - _vkd3d = self.args.vkd3d - _nvapi = self.args.nvapi - _latencyflex = self.args.latencyflex - mng = Manager(g_settings=self.settings, is_cli=True) - mng.check_bottles() - - valid_parameters = BottleConfig().Parameters.keys() - - if _bottle not in mng.local_bottles: - sys.stderr.write(f"Bottle {_bottle} not found\n") - exit(1) - - bottle = mng.local_bottles[_bottle] - - if _params is not None: - _params = _params.split(",") - _params = [p.split(":") for p in _params] - for k, v in _params: - if k not in valid_parameters: - sys.stderr.write(f"Invalid parameter {k}\n") - exit(1) - - if v.lower() == "true": - v = True - elif v.lower() == "false": - v = False - else: - try: - v = int(v) - except ValueError: - pass - - mng.update_config(bottle, k, v, scope="Parameters") - - if _env_var is not None and "=" in _env_var: - k, v = _env_var.split("=", 1) - mng.update_config(bottle, k, v, scope="Environment_Variables") - - if _win is not None: - RegKeys(bottle).lg_set_windows(_win) - - if _runner is not None: - Runner.runner_update(bottle, mng, _runner) - - if _dxvk is not None: - mng.check_dxvk(False) - - if _dxvk not in mng.dxvk_available: - sys.stderr.write(f"DXVK version {_dxvk} not available\n") - exit(1) - - if mng.install_dll_component(bottle, "dxvk", version=_dxvk): - mng.update_config(bottle, "DXVK", _dxvk) - - if _vkd3d is not None: - mng.check_vkd3d(False) - - if _vkd3d not in mng.vkd3d_available: - sys.stderr.write(f"VKD3D version {_vkd3d} not available\n") - exit(1) - - if mng.install_dll_component(bottle, "vkd3d", version=_vkd3d): - mng.update_config(bottle, "VKD3D", _vkd3d) - - if _nvapi is not None: - mng.check_nvapi(False) - - if _nvapi not in mng.nvapi_available: - sys.stderr.write(f"NVAPI version {_nvapi} not available\n") - exit(1) - - if mng.install_dll_component(bottle, "nvapi", version=_nvapi): - mng.update_config(bottle, "NVAPI", _nvapi) - - if _latencyflex is not None: - mng.check_latencyflex(False) - - if _latencyflex not in mng.latencyflex_available: - sys.stderr.write(f"LatencyFlex version {_latencyflex} not available\n") - exit(1) - - if mng.install_dll_component(bottle, "latencyflex", version=_latencyflex): - mng.update_config(bottle, "LatencyFlex", _latencyflex) - - # endregion - - # region NEW - def new_bottle(self): - _name = self.args.bottle_name - _environment = self.args.environment - _custom_environment = self.args.custom_environment - _arch = "win64" if self.args.arch is None else self.args.arch - _runner = self.args.runner - _dxvk = self.args.dxvk - _vkd3d = self.args.vkd3d - _nvapi = self.args.nvapi - _latencyflex = self.args.latencyflex - mng = Manager(g_settings=self.settings, is_cli=True) - mng.checks() - - mng.create_bottle( - name=_name, - environment=_environment, - runner=_runner, - dxvk=_dxvk, - vkd3d=_vkd3d, - nvapi=_nvapi, - latencyflex=_latencyflex, - arch=_arch, - custom_environment=_custom_environment, - ) - - # endregion - - # region RUN - def run_program(self): - _bottle = self.args.bottle - _program = self.args.program - _keep = self.args.keep_args - _args = " ".join(self.args.args) - _executable = self.args.executable - - mng = Manager(g_settings=self.settings, is_cli=True) - mng.checks() - - if _bottle.startswith('"') and _bottle.endswith('"'): - _bottle = _bottle[1:-1] - elif _bottle.startswith("'") and _bottle.endswith("'"): - _bottle = _bottle[1:-1] - - for b in mng.local_bottles.keys(): - if b == _bottle: - break - else: - sys.stderr.write(f"Bottle {_bottle} not found\n") - exit(1) - - bottle = mng.local_bottles[_bottle] - programs = mng.get_programs(bottle) - - if _program is not None: - if _executable is not None: - sys.stderr.write("Cannot specify both --program and --executable\n") - exit(1) - - if _program not in [p["name"] for p in programs]: - sys.stderr.write(f"Program {_program} not found\n") - exit(1) - - program = [p for p in programs if p["name"] == _program][0] - _executable = program.get("path", "") - _program_args = program.get("arguments") - if _keep and _program_args: - _args = _program_args + " " + _args - program.get("pre_script", None) - program.get("post_script", None) - program.get("folder", None) - program.get("midi_soundfont", None) - - program.get("dxvk") - program.get("vkd3d") - program.get("dxvk_nvapi") - program.get("fsr") - program.get("gamescope") - program.get("virtual_desktop") - - WineExecutor.run_program(bottle, program | {"arguments": _args}) - - elif _executable: - _executable = _executable.replace("file://", "") - if _executable.startswith('"') and _executable.endswith('"'): - _executable = _executable[1:-1] - elif _executable.startswith("'") and _executable.endswith("'"): - _executable = _executable[1:-1] - - WineExecutor( - bottle, - exec_path=_executable, - args=_args, - ).run_cli() - else: - sys.stderr.write( - "No program or executable specified, you must use either --program or --executable\n" - ) - exit(1) - - # endregion - - # region SHELL - def run_shell(self): - _bottle = self.args.bottle - _input = self.args.input - mng = Manager(g_settings=self.settings, is_cli=True) - mng.checks() - - if _bottle not in mng.local_bottles: - sys.stderr.write(f"Bottle {_bottle} not found\n") - exit(1) - - bottle = mng.local_bottles[_bottle] - winecommand = WineCommand(config=bottle, command=_input, communicate=True) - res = winecommand.run() - if not res.ok: - sys.stdout.write(res.message) - sys.stdout.write(res.data) - - # endregion - - # region STANDALONE - def generate_standalone(self): - _bottle = self.args.bottle - mng = Manager(g_settings=self.settings, is_cli=True) - mng.checks() - - if _bottle not in mng.local_bottles: - sys.stderr.write(f"Bottle {_bottle} not found\n") - exit(1) - - bottle = mng.local_bottles[_bottle] - path = ManagerUtils.get_bottle_path(bottle) - standalone_path = os.path.join(path, "standalone") - winecommand = WineCommand(config=bottle, command='"$@"') - env = winecommand.get_env(return_clean_env=True) - cmd = winecommand.get_cmd('"$@"', return_clean_cmd=True) - winecommand.command.replace( - "/usr/lib/extensions/vulkan/MangoHud/bin/mangohud", "" - ) - - if os.path.isfile(standalone_path): - os.remove(standalone_path) - - with open(standalone_path, "w") as f: - f.write("#!/bin/bash\n") - for k, v in env.items(): - f.write(f"export {k}='{v}'\n") - f.write(f"{cmd}\n") - - os.chmod(os.path.join(path, "standalone"), 0o755) - sys.stdout.write(f"Standalone generated in {path}\n") - sys.stdout.write("Re-generate after every bottle change.\n") - - -if __name__ == "__main__": - cli = CLI() diff --git a/bottles/frontend/meson.build b/bottles/frontend/meson.build index 5bf84dd5d2c..7372cfd3456 100644 --- a/bottles/frontend/meson.build +++ b/bottles/frontend/meson.build @@ -74,15 +74,6 @@ gnome.compile_resources('bottles', install_dir: pkgdatadir, ) -configure_file( - input: 'cli.py', - output: 'bottles-cli', - configuration: conf, - install: true, - install_dir: get_option('bindir'), - install_mode: ['rwxr-xr-x'] -) - configure_file( input: 'bottles.py', output: 'bottles', diff --git a/bottles/tests/backend/manager/test_manager.py b/bottles/tests/backend/manager/test_manager.py index 7651141c78a..751b882a0ca 100644 --- a/bottles/tests/backend/manager/test_manager.py +++ b/bottles/tests/backend/manager/test_manager.py @@ -5,11 +5,9 @@ def test_manager_is_singleton(): - assert Manager(is_cli=True) is Manager( - is_cli=True - ), "Manager should be singleton object" - assert Manager(is_cli=True) is Manager( - g_settings=GSettingsStub(), is_cli=True + assert Manager() is Manager(), "Manager should be singleton object" + assert Manager() is Manager( + g_settings=GSettingsStub() ), "Manager should be singleton even with different argument" From 86ccc549d8c8072d176ca3bd73bdd4939aaf5588 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Mon, 20 Jan 2025 22:39:42 -0500 Subject: [PATCH 095/146] backend: Remove repair_bottle --- bottles/backend/managers/manager.py | 32 ----------------------------- 1 file changed, 32 deletions(-) diff --git a/bottles/backend/managers/manager.py b/bottles/backend/managers/manager.py index 2c9d72ce6eb..c38e4948ab1 100644 --- a/bottles/backend/managers/manager.py +++ b/bottles/backend/managers/manager.py @@ -1491,38 +1491,6 @@ def delete_bottle(self, config: BottleConfig) -> bool: logging.info(f"Deleted the bottle in: {path}") return True - def repair_bottle(self, config: BottleConfig) -> bool: - """ - This function tries to repair a broken bottle, creating a - new bottle configuration with the latest runner. Each fixed - bottle will use the Custom environment. - TODO: will be replaced by the BottlesManager class. - """ - logging.info(f"Trying to repair the bottle: [{config.Name}]…") - - wineboot = WineBoot(config) - bottle_path = f"{Paths.bottles}/{config.Name}" - - # create new config with path as name and Custom environment - new_config = BottleConfig() - new_config.Name = config.Name - new_config.Runner = self.get_latest_runner() - new_config.Path = config.Name - new_config.Environment = "Custom" - new_config.Creation_Date = str(datetime.now()) - new_config.Update_Date = str(datetime.now()) - - saved = new_config.dump(os.path.join(bottle_path, "bottle.yml")) - if not saved.status: - return False - - # Execute wineboot in bottle to generate missing files - wineboot.init() - - # Update bottles - self.update_bottles() - return True - def install_dll_component( self, config: BottleConfig, From ecf49a7707b675e3d0181c7543d4e3c4cf3d97e7 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Mon, 20 Jan 2025 23:14:34 -0500 Subject: [PATCH 096/146] backend: Remove RepositoryManager --- bottles/backend/managers/component.py | 5 +- bottles/backend/managers/dependency.py | 5 +- bottles/backend/managers/installer.py | 5 +- bottles/backend/managers/manager.py | 4 - bottles/backend/managers/meson.build | 1 - bottles/backend/managers/repository.py | 151 ------------------------- bottles/backend/state.py | 1 - 7 files changed, 12 insertions(+), 160 deletions(-) delete mode 100644 bottles/backend/managers/repository.py diff --git a/bottles/backend/managers/component.py b/bottles/backend/managers/component.py index ba4bfba239a..7eb46456789 100644 --- a/bottles/backend/managers/component.py +++ b/bottles/backend/managers/component.py @@ -38,6 +38,7 @@ from bottles.backend.utils.file import FileUtils from bottles.backend.utils.generic import is_glibc_min_available from bottles.backend.utils.manager import ManagerUtils +from bottles.backend.repos.component import ComponentRepo logging = Logger() @@ -46,7 +47,9 @@ class ComponentManager: def __init__(self, manager): self.__manager = manager - self.__repo = manager.repository_manager.get_repo("components") + + url = "https://proxy.usebottles.com/repo/components/" + self.__repo = ComponentRepo(url, "") @lru_cache def get_component(self, name: str, plain: bool = False) -> dict: diff --git a/bottles/backend/managers/dependency.py b/bottles/backend/managers/dependency.py index 29084a02d64..02217b3d123 100644 --- a/bottles/backend/managers/dependency.py +++ b/bottles/backend/managers/dependency.py @@ -38,6 +38,7 @@ from bottles.backend.wine.regsvr32 import Regsvr32 from bottles.backend.wine.uninstaller import Uninstaller from bottles.backend.wine.winedbg import WineDbg +from bottles.backend.repos.dependency import DependencyRepo logging = Logger() @@ -45,7 +46,9 @@ class DependencyManager: def __init__(self, manager): self.__manager = manager - self.__repo = manager.repository_manager.get_repo("dependencies") + + url = "https://proxy.usebottles.com/repo/dependencies/" + self.__repo = DependencyRepo(url, "") @lru_cache def get_dependency(self, name: str, plain: bool = False) -> str | dict | bool: diff --git a/bottles/backend/managers/installer.py b/bottles/backend/managers/installer.py index bee8140797a..b8aad7bc3b4 100644 --- a/bottles/backend/managers/installer.py +++ b/bottles/backend/managers/installer.py @@ -29,6 +29,7 @@ from bottles.backend.models.result import Result from bottles.backend.utils.manager import ManagerUtils from bottles.backend.utils.wine import WineUtils +from bottles.backend.repos.installer import InstallerRepo from bottles.backend.wine.executor import WineExecutor from bottles.backend.wine.winecommand import WineCommand @@ -38,10 +39,12 @@ class InstallerManager: def __init__(self, manager): self.__manager = manager - self.__repo = manager.repository_manager.get_repo("installers") self.__component_manager = manager.component_manager self.__local_resources = {} + url = "https://proxy.usebottles.com/repo/programs/" + self.__repo = InstallerRepo(url, "") + @lru_cache def get_review(self, installer_name, parse: bool = True) -> str: """Return an installer review from the repository (as HTML)""" diff --git a/bottles/backend/managers/manager.py b/bottles/backend/managers/manager.py index c38e4948ab1..986f9c72b90 100644 --- a/bottles/backend/managers/manager.py +++ b/bottles/backend/managers/manager.py @@ -43,7 +43,6 @@ from bottles.backend.managers.importer import ImportManager from bottles.backend.managers.installer import InstallerManager from bottles.backend.managers.library import LibraryManager -from bottles.backend.managers.repository import RepositoryManager from bottles.backend.managers.steam import SteamManager from bottles.backend.managers.template import TemplateManager from bottles.backend.managers.ubisoftconnect import UbisoftConnectManager @@ -127,9 +126,6 @@ def __init__( ) # sub-managers - self.repository_manager = RepositoryManager() - - times["RepositoryManager"] = time.time() self.versioning_manager = VersioningManager(self) times["VersioningManager"] = time.time() self.component_manager = ComponentManager(self) diff --git a/bottles/backend/managers/meson.build b/bottles/backend/managers/meson.build index e682c0c3b44..1829d283956 100644 --- a/bottles/backend/managers/meson.build +++ b/bottles/backend/managers/meson.build @@ -15,7 +15,6 @@ bottles_sources = [ 'importer.py', 'conf.py', 'journal.py', - 'repository.py', 'template.py', 'sandbox.py', 'steam.py', diff --git a/bottles/backend/managers/repository.py b/bottles/backend/managers/repository.py deleted file mode 100644 index 41401ccb11d..00000000000 --- a/bottles/backend/managers/repository.py +++ /dev/null @@ -1,151 +0,0 @@ -# repository.py -# -# Copyright 2022 brombinmirko -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, in version 3 of the License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# - -import os - -import pycurl - -from bottles.backend.logger import Logger -from bottles.backend.models.result import Result -from bottles.backend.params import APP_VERSION -from bottles.backend.repos.component import ComponentRepo -from bottles.backend.repos.dependency import DependencyRepo -from bottles.backend.repos.installer import InstallerRepo -from bottles.backend.state import SignalManager, Signals -from bottles.backend.utils.threading import RunAsync - -logging = Logger() - - -class RepositoryManager: - __repositories = { - "components": { - "url": "https://proxy.usebottles.com/repo/components/", - "index": "", - "cls": ComponentRepo, - }, - "dependencies": { - "url": "https://proxy.usebottles.com/repo/dependencies/", - "index": "", - "cls": DependencyRepo, - }, - "installers": { - "url": "https://proxy.usebottles.com/repo/programs/", - "index": "", - "cls": InstallerRepo, - }, - } - - def __init__(self): - self.do_get_index = True - self.aborted_connections = 0 - SignalManager.connect(Signals.ForceStopNetworking, self.__stop_index) - - self.__check_personals() - self.__get_index() - - def get_repo(self, name: str): - if name in self.__repositories: - repo = self.__repositories[name] - return repo["cls"](repo["url"], repo["index"]) - - logging.error(f"Repository {name} not found") - - def __check_personals(self): - _personals = {} - - if "PERSONAL_COMPONENTS" in os.environ: - _personals["components"] = os.environ["PERSONAL_COMPONENTS"] - - if "PERSONAL_DEPENDENCIES" in os.environ: - _personals["dependencies"] = os.environ["PERSONAL_DEPENDENCIES"] - - if "PERSONAL_INSTALLERS" in os.environ: - _personals["installers"] = os.environ["PERSONAL_INSTALLERS"] - - if not _personals: - return - - for repo in self.__repositories: - if repo not in _personals: - continue - - _url = _personals[repo] - self.__repositories[repo]["url"] = _url - logging.info(f"Using personal {repo} repository at {_url}") - - def __curl_progress(self, _download_t, _download_d, _upload_t, _upload_d): - if self.do_get_index: - return pycurl.E_OK - else: - self.aborted_connections += 1 - return pycurl.E_ABORTED_BY_CALLBACK - - def __stop_index(self, res: Result): - if res.status: - self.do_get_index = False - - def __get_index(self): - total = len(self.__repositories) - - threads = [] - - for repo, data in self.__repositories.items(): - - def query(_repo, _data): - __index = os.path.join(_data["url"], f"{APP_VERSION}.yml") - __fallback = os.path.join(_data["url"], "index.yml") - - for url in (__index, __fallback): - c = pycurl.Curl() - c.setopt(c.URL, url) - c.setopt(c.NOBODY, True) - c.setopt(c.FOLLOWLOCATION, True) - c.setopt(c.TIMEOUT, 10) - c.setopt(c.NOPROGRESS, False) - c.setopt(c.XFERINFOFUNCTION, self.__curl_progress) - - try: - c.perform() - except pycurl.error as e: - if url is not __index: - logging.error( - f"Could not get index for {_repo} repository: {e}" - ) - continue - - if url.startswith("file://") or c.getinfo(c.RESPONSE_CODE) == 200: - _data["index"] = url - SignalManager.send( - Signals.RepositoryFetched, Result(True, data=total) - ) - break - - c.close() - else: - SignalManager.send( - Signals.RepositoryFetched, Result(False, data=total) - ) - logging.error(f"Could not get index for {_repo} repository") - - thread = RunAsync(query, _repo=repo, _data=data) - threads.append(thread) - - for t in threads: - t.join() - - self.do_get_index = True diff --git a/bottles/backend/state.py b/bottles/backend/state.py index e29bbe18862..07b2d02a1f7 100644 --- a/bottles/backend/state.py +++ b/bottles/backend/state.py @@ -33,7 +33,6 @@ class Signals(Enum): ForceStopNetworking = ( "LoadingView.stop_networking" # status(bool): Force Stop network operations ) - RepositoryFetched = "RepositoryManager.repo_fetched" # status: fetch success or not, data(int): total repositories NetworkStatusChanged = ( "ConnectionUtils.status_changed" # status(bool): network ready or not ) From 7606cd67e16240b7daddc7a330b69f9e6ff4660d Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Tue, 21 Jan 2025 16:01:13 -0500 Subject: [PATCH 097/146] backend: Remove support for removing temp files --- bottles/backend/managers/manager.py | 13 ------------- bottles/frontend/preferences.blp | 10 ---------- bottles/frontend/preferences.py | 4 ---- 3 files changed, 27 deletions(-) diff --git a/bottles/backend/managers/manager.py b/bottles/backend/managers/manager.py index 986f9c72b90..201eb478eda 100644 --- a/bottles/backend/managers/manager.py +++ b/bottles/backend/managers/manager.py @@ -182,7 +182,6 @@ def checks(self, install_latest=False, first_run=False) -> Result: if first_run: self.organize_components() - self.__clear_temp() self.organize_dependencies() @@ -193,18 +192,6 @@ def checks(self, install_latest=False, first_run=False) -> Result: return rv - def __clear_temp(self, force: bool = False): - """Clears the temp directory if user setting allows it. Use the force - parameter to force clearing the directory. - """ - if self.settings.get_boolean("temp") or force: - try: - shutil.rmtree(Paths.temp) - os.makedirs(Paths.temp, exist_ok=True) - logging.info("Temp directory cleaned successfully!") - except FileNotFoundError: - self.check_app_dirs() - def update_bottles(self, silent: bool = False): """Checks for new bottles and update the list view.""" self.check_bottles(silent) diff --git a/bottles/frontend/preferences.blp b/bottles/frontend/preferences.blp index c1fcf649f00..53394c9630a 100644 --- a/bottles/frontend/preferences.blp +++ b/bottles/frontend/preferences.blp @@ -49,16 +49,6 @@ template $PreferencesWindow: Adw.PreferencesWindow { } } - Adw.ActionRow { - title: _("Temp Files"); - subtitle: _("Clean temp files when Bottles launches?"); - activatable-widget: switch_temp; - - Switch switch_temp { - valign: center; - } - } - Adw.ActionRow { title: _("Close Bottles After Starting a Program"); subtitle: _("Close Bottles after starting a program from the file manager."); diff --git a/bottles/frontend/preferences.py b/bottles/frontend/preferences.py index f58a056e2e5..fdcdf722cfa 100644 --- a/bottles/frontend/preferences.py +++ b/bottles/frontend/preferences.py @@ -47,7 +47,6 @@ class PreferencesWindow(Adw.PreferencesWindow): switch_theme = Gtk.Template.Child() switch_notifications = Gtk.Template.Child() switch_force_offline = Gtk.Template.Child() - switch_temp = Gtk.Template.Child() switch_release_candidate = Gtk.Template.Child() switch_steam = Gtk.Template.Child() switch_sandbox = Gtk.Template.Child() @@ -104,9 +103,6 @@ def __init__(self, window, **kwargs): "active", Gio.SettingsBindFlags.DEFAULT, ) - self.settings.bind( - "temp", self.switch_temp, "active", Gio.SettingsBindFlags.DEFAULT - ) # Connect RC signal to another func self.settings.bind( "release-candidate", From ac79535711ad483fe5f19321bd172e552ea7070a Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Tue, 21 Jan 2025 20:11:48 -0500 Subject: [PATCH 098/146] globals: Add class method for retrieving list of paths --- bottles/backend/globals.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/bottles/backend/globals.py b/bottles/backend/globals.py index 8123b2396ba..71b7082c922 100644 --- a/bottles/backend/globals.py +++ b/bottles/backend/globals.py @@ -60,6 +60,24 @@ def is_vkbasalt_available(): return True return False + @classmethod + def get_components_paths(cls) -> list[str]: + """Retrieve list of components' paths.""" + + return [ + cls.temp, + cls.runtimes, + cls.winebridge, + cls.runners, + cls.bottles, + cls.steam, + cls.dxvk, + cls.vkd3d, + cls.nvapi, + cls.latencyflex, + cls.templates, + ] + class TrdyPaths: # External managers paths From 0cfd5ef957d56990666e23bc276114efc8c2d949 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Tue, 21 Jan 2025 20:25:32 -0500 Subject: [PATCH 099/146] manager: Use components_paths getter method --- bottles/backend/managers/manager.py | 49 +---------------------------- 1 file changed, 1 insertion(+), 48 deletions(-) diff --git a/bottles/backend/managers/manager.py b/bottles/backend/managers/manager.py index 201eb478eda..d77d29b7411 100644 --- a/bottles/backend/managers/manager.py +++ b/bottles/backend/managers/manager.py @@ -157,7 +157,6 @@ def checks(self, install_latest=False, first_run=False) -> Result: rv = Result(status=True, data={}) self.check_app_dirs() - rv.data["check_app_dirs"] = time.time() self.check_dxvk(install_latest) or rv.set_status(False) rv.data["check_dxvk"] = time.time() @@ -202,53 +201,7 @@ def check_app_dirs(self): Checks for the existence of the bottles' directories, and creates them if they don't exist. """ - if not os.path.isdir(Paths.runners): - logging.info("Runners path doesn't exist, creating now.") - os.makedirs(Paths.runners, exist_ok=True) - - if not os.path.isdir(Paths.runtimes): - logging.info("Runtimes path doesn't exist, creating now.") - os.makedirs(Paths.runtimes, exist_ok=True) - - if not os.path.isdir(Paths.winebridge): - logging.info("WineBridge path doesn't exist, creating now.") - os.makedirs(Paths.winebridge, exist_ok=True) - - if not os.path.isdir(Paths.bottles): - logging.info("Bottles path doesn't exist, creating now.") - os.makedirs(Paths.bottles, exist_ok=True) - - if ( - self.settings.get_boolean("steam-proton-support") - and self.steam_manager.is_steam_supported - ): - if not os.path.isdir(Paths.steam): - logging.info("Steam path doesn't exist, creating now.") - os.makedirs(Paths.steam, exist_ok=True) - - if not os.path.isdir(Paths.dxvk): - logging.info("Dxvk path doesn't exist, creating now.") - os.makedirs(Paths.dxvk, exist_ok=True) - - if not os.path.isdir(Paths.vkd3d): - logging.info("Vkd3d path doesn't exist, creating now.") - os.makedirs(Paths.vkd3d, exist_ok=True) - - if not os.path.isdir(Paths.nvapi): - logging.info("Nvapi path doesn't exist, creating now.") - os.makedirs(Paths.nvapi, exist_ok=True) - - if not os.path.isdir(Paths.templates): - logging.info("Templates path doesn't exist, creating now.") - os.makedirs(Paths.templates, exist_ok=True) - - if not os.path.isdir(Paths.temp): - logging.info("Temp path doesn't exist, creating now.") - os.makedirs(Paths.temp, exist_ok=True) - - if not os.path.isdir(Paths.latencyflex): - logging.info("LatencyFleX path doesn't exist, creating now.") - os.makedirs(Paths.latencyflex, exist_ok=True) + map(lambda path: os.makedirs(path, exist_ok=True), Paths.get_components_paths()) @RunAsync.run_async def organize_components(self): From c935ae790bac7a06970ae89f403c4494acf20de9 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Tue, 21 Jan 2025 22:40:20 -0500 Subject: [PATCH 100/146] frontend: Remove versioning --- bottles/frontend/bottle-details-page.blp | 10 -- bottles/frontend/bottle_details_page.py | 15 -- bottles/frontend/bottle_details_view.py | 7 - bottles/frontend/bottles.gresource.xml | 5 - bottles/frontend/details-preferences-page.blp | 44 ----- bottles/frontend/details-versioning-page.blp | 88 ---------- bottles/frontend/details_preferences_page.py | 55 +----- bottles/frontend/details_versioning_page.py | 161 ------------------ bottles/frontend/exclusion-pattern-row.blp | 15 -- .../frontend/exclusion-patterns-dialog.blp | 40 ----- bottles/frontend/exclusion_patterns_dialog.py | 111 ------------ bottles/frontend/meson.build | 9 - bottles/frontend/state-row.blp | 24 --- bottles/frontend/state_row.py | 128 -------------- .../frontend/upgrade-versioning-dialog.blp | 131 -------------- bottles/frontend/upgrade_versioning_dialog.py | 81 --------- 16 files changed, 1 insertion(+), 923 deletions(-) delete mode 100644 bottles/frontend/details-versioning-page.blp delete mode 100644 bottles/frontend/details_versioning_page.py delete mode 100644 bottles/frontend/exclusion-pattern-row.blp delete mode 100644 bottles/frontend/exclusion-patterns-dialog.blp delete mode 100644 bottles/frontend/exclusion_patterns_dialog.py delete mode 100644 bottles/frontend/state-row.blp delete mode 100644 bottles/frontend/state_row.py delete mode 100644 bottles/frontend/upgrade-versioning-dialog.blp delete mode 100644 bottles/frontend/upgrade_versioning_dialog.py diff --git a/bottles/frontend/bottle-details-page.blp b/bottles/frontend/bottle-details-page.blp index 670faec8798..29973e9377e 100644 --- a/bottles/frontend/bottle-details-page.blp +++ b/bottles/frontend/bottle-details-page.blp @@ -373,16 +373,6 @@ template $BottleDetailsPage: Adw.PreferencesPage { } } - Adw.ActionRow row_snapshots { - activatable: true; - title: _("Snapshots"); - subtitle: _("Create and manage bottle states."); - - Image { - icon-name: "go-next-symbolic"; - } - } - Adw.ActionRow row_taskmanager { activatable: true; title: _("Task Manager"); diff --git a/bottles/frontend/bottle_details_page.py b/bottles/frontend/bottle_details_page.py index 57e44ee046a..83553fe0c96 100644 --- a/bottles/frontend/bottle_details_page.py +++ b/bottles/frontend/bottle_details_page.py @@ -42,7 +42,6 @@ from bottles.frontend.gtk import GtkUtils from bottles.frontend.program_row import ProgramRow from bottles.frontend.duplicate_dialog import DuplicateDialog -from bottles.frontend.upgrade_versioning_dialog import UpgradeVersioningDialog @Gtk.Template(resource_path="/com/usebottles/bottles/bottle-details-page.ui") @@ -64,7 +63,6 @@ class BottleDetailsPage(Adw.PreferencesPage): row_winecfg = Gtk.Template.Child() row_preferences = Gtk.Template.Child() row_dependencies = Gtk.Template.Child() - row_snapshots = Gtk.Template.Child() row_taskmanager = Gtk.Template.Child() row_debug = Gtk.Template.Child() row_explorer = Gtk.Template.Child() @@ -123,7 +121,6 @@ def __init__(self, details, config, **kwargs): self.popover_exec_settings.connect("closed", self.__run_executable_with_args) self.row_preferences.connect("activated", self.__change_page, "preferences") self.row_dependencies.connect("activated", self.__change_page, "dependencies") - self.row_snapshots.connect("activated", self.__change_page, "versioning") self.row_taskmanager.connect("activated", self.__change_page, "taskmanager") self.row_winecfg.connect("activated", self.run_winecfg) self.row_debug.connect("activated", self.run_debug) @@ -222,10 +219,6 @@ def set_config(self, config: BottleConfig): self.__set_steam_rules() - # check for old versioning system enabled - if config.Versioning: - self.__upgrade_versioning() - if ( config.Runner not in self.manager.runners_available and not self.config.Environment == "Steam" @@ -502,14 +495,6 @@ def __duplicate(self, widget): new_window = DuplicateDialog(self) new_window.present() - def __upgrade_versioning(self): - """ - This function pop up the upgrade versioning dialog, so the user can - upgrade the versioning system from old Bottles built-in to FVS. - """ - new_window = UpgradeVersioningDialog(self) - new_window.present() - def __confirm_delete(self, widget): """ This function pop up to delete confirm dialog. If user confirm diff --git a/bottles/frontend/bottle_details_view.py b/bottles/frontend/bottle_details_view.py index afe50ab1f82..ea2e573440a 100644 --- a/bottles/frontend/bottle_details_view.py +++ b/bottles/frontend/bottle_details_view.py @@ -29,7 +29,6 @@ from bottles.frontend.details_installers_view import DetailsInstallersView from bottles.frontend.details_dependencies_view import DetailsDependenciesView from bottles.frontend.details_preferences_page import DetailsPreferencesPage -from bottles.frontend.details_versioning_page import DetailsVersioningPage from bottles.frontend.details_task_manager_view import DetailsTaskManagerView @@ -70,7 +69,6 @@ def __init__(self, window, config: BottleConfig | None = None, **kwargs): self.window = window self.manager = window.manager - self.versioning_manager = window.manager.versioning_manager self.config = config self.queue = QueueManager(add_fn=self.lock_back, end_fn=self.unlock_back) @@ -78,7 +76,6 @@ def __init__(self, window, config: BottleConfig | None = None, **kwargs): self.view_installers = DetailsInstallersView(self, config) self.view_dependencies = DetailsDependenciesView(self, config) self.view_preferences = DetailsPreferencesPage(self, config) - self.view_versioning = DetailsVersioningPage(self, config) self.view_taskmanager = DetailsTaskManagerView(self, config) self.btn_back.connect("clicked", self.go_back) @@ -120,8 +117,6 @@ def __on_page_change(self, *_args): if page == "dependencies": self.set_actions(self.view_dependencies.actions) self.view_dependencies.update(config=self.config) - elif page == "versioning": - self.set_actions(self.view_versioning.actions) elif page == "installers": self.set_actions(self.view_installers.actions) elif page == "taskmanager": @@ -167,7 +162,6 @@ def ui_update(): self.stack_bottle.add_named(self.view_preferences, "preferences") self.stack_bottle.add_named(self.view_dependencies, "dependencies") - self.stack_bottle.add_named(self.view_versioning, "versioning") self.stack_bottle.add_named(self.view_installers, "installers") self.stack_bottle.add_named(self.view_taskmanager, "taskmanager") @@ -200,7 +194,6 @@ def set_config(self, config: BottleConfig, rebuild_pages=True): self.view_preferences.set_config(config=config) self.view_taskmanager.set_config(config=config) self.view_installers.update(config=config) - self.view_versioning.update(config=config) if rebuild_pages: self.build_pages() diff --git a/bottles/frontend/bottles.gresource.xml b/bottles/frontend/bottles.gresource.xml index de4e8a76360..9f08d7e169e 100644 --- a/bottles/frontend/bottles.gresource.xml +++ b/bottles/frontend/bottles.gresource.xml @@ -14,7 +14,6 @@ dependency-entry-row.ui program-row.ui importer-row.ui - state-row.ui installer-row.ui dll-override-entry.ui env-var-entry.ui @@ -22,13 +21,11 @@ drive-entry.ui library-entry.ui local-resource-row.ui - exclusion-pattern-row.ui bottle-details-view.ui bottle-details-page.ui details-dependencies-view.ui details-installers-view.ui details-preferences-page.ui - details-versioning-page.ui details-task-manager-view.ui preferences.ui importer-view.ui @@ -51,8 +48,6 @@ bottle-picker-dialog.ui proton-alert-dialog.ui dependencies-check-dialog.ui - exclusion-patterns-dialog.ui - upgrade-versioning-dialog.ui vmtouch-dialog.ui onboard-dialog.ui diff --git a/bottles/frontend/details-preferences-page.blp b/bottles/frontend/details-preferences-page.blp index 58db442ef24..83ba7defa02 100644 --- a/bottles/frontend/details-preferences-page.blp +++ b/bottles/frontend/details-preferences-page.blp @@ -402,48 +402,4 @@ template $DetailsPreferencesPage: Adw.PreferencesPage { } } } - - Adw.PreferencesGroup { - title: _("Snapshots"); - - Adw.ActionRow { - activatable-widget: switch_auto_versioning; - title: _("Automatic Snapshots"); - subtitle: _("Automatically create snapshots before installing software or changing settings."); - - Switch switch_auto_versioning { - valign: center; - } - } - - Adw.ActionRow { - activatable-widget: switch_versioning_compression; - title: _("Compression"); - subtitle: _("Compress snapshots to reduce space. This will slow down the creation of snapshots."); - - Switch switch_versioning_compression { - valign: center; - } - } - - Adw.ActionRow { - activatable-widget: switch_versioning_patterns; - title: _("Use Exclusion Patterns"); - subtitle: _("Exclude paths in snapshots."); - - Button btn_manage_versioning_patterns { - tooltip-text: _("Manage Patterns"); - valign: center; - icon-name: "applications-system-symbolic"; - - styles [ - "flat", - ] - } - - Switch switch_versioning_patterns { - valign: center; - } - } - } } diff --git a/bottles/frontend/details-versioning-page.blp b/bottles/frontend/details-versioning-page.blp deleted file mode 100644 index 99bc65a74bf..00000000000 --- a/bottles/frontend/details-versioning-page.blp +++ /dev/null @@ -1,88 +0,0 @@ -using Gtk 4.0; -using Adw 1; - -template $DetailsVersioningPage: Adw.PreferencesPage { - Adw.PreferencesPage pref_page { - Adw.PreferencesGroup { - ListBox list_states { - selection-mode: none; - - styles [ - "boxed-list", - ] - } - } - } - - Adw.StatusPage status_page { - icon-name: "preferences-system-time-symbolic"; - title: _("No Snapshots Found"); - description: _("Create your first snapshot to start saving states of your preferences."); - } -} - -Popover pop_context { - styles [ - "menu", - ] - - Box { - orientation: vertical; - margin-top: 6; - margin-bottom: 6; - margin-start: 6; - margin-end: 6; - - $GtkModelButton btn_help { - tooltip-text: _("Read Documentation"); - text: _("Documentation"); - } - } -} - -Popover pop_state { - Box { - orientation: vertical; - spacing: 6; - - styles [ - "menu", - ] - - Box { - Entry entry_state_message { - hexpand: true; - placeholder-text: _("A short comment"); - } - - Button btn_save { - tooltip-text: _("Save the bottle state."); - halign: end; - icon-name: "object-select-symbolic"; - - styles [ - "suggested-action", - ] - } - - styles [ - "linked", - ] - } - } -} - -Box actions { - spacing: 6; - - MenuButton btn_add { - tooltip-text: _("Create new Snapshot"); - popover: pop_state; - icon-name: "list-add-symbolic"; - } - - MenuButton { - popover: pop_context; - icon-name: "view-more-symbolic"; - } -} diff --git a/bottles/frontend/details_preferences_page.py b/bottles/frontend/details_preferences_page.py index ce58232e3fb..8d96591a00a 100644 --- a/bottles/frontend/details_preferences_page.py +++ b/bottles/frontend/details_preferences_page.py @@ -49,7 +49,6 @@ from bottles.frontend.environment_variables_dialog import ( EnvironmentVariablesDialog, ) -from bottles.frontend.exclusion_patterns_dialog import ExclusionPatternsDialog from bottles.frontend.fsr_dialog import FsrDialog from bottles.frontend.gamescope_dialog import GamescopeDialog from bottles.frontend.mangohud_dialog import MangoHudDialog @@ -72,7 +71,6 @@ class DetailsPreferencesPage(Adw.PreferencesPage): btn_manage_fsr = Gtk.Template.Child() btn_manage_mangohud = Gtk.Template.Child() btn_manage_sandbox = Gtk.Template.Child() - btn_manage_versioning_patterns = Gtk.Template.Child() btn_manage_vmtouch = Gtk.Template.Child() btn_cwd_reset = Gtk.Template.Child() btn_cwd = Gtk.Template.Child() @@ -98,9 +96,6 @@ class DetailsPreferencesPage(Adw.PreferencesPage): switch_discrete = Gtk.Template.Child() switch_steam_runtime = Gtk.Template.Child() switch_sandbox = Gtk.Template.Child() - switch_versioning_compression = Gtk.Template.Child() - switch_auto_versioning = Gtk.Template.Child() - switch_versioning_patterns = Gtk.Template.Child() switch_vmtouch = Gtk.Template.Child() combo_runner = Gtk.Template.Child() combo_dxvk = Gtk.Template.Child() @@ -221,9 +216,6 @@ def __init__(self, details, config, **kwargs): self.btn_manage_vmtouch.connect( "clicked", self.__show_feature_dialog, VmtouchDialog ) - self.btn_manage_versioning_patterns.connect( - "clicked", self.__show_feature_dialog, ExclusionPatternsDialog - ) self.btn_cwd.connect("clicked", self.choose_cwd) self.btn_cwd_reset.connect("clicked", self.reset_cwd, True) self.switch_mangohud.connect("state-set", self.__toggle_feature_cb, "mangohud") @@ -239,15 +231,6 @@ def __init__(self, details, config, **kwargs): self.switch_discrete.connect( "state-set", self.__toggle_feature_cb, "discrete_gpu" ) - self.switch_versioning_compression.connect( - "state-set", self.__toggle_versioning_compression - ) - self.switch_auto_versioning.connect( - "state-set", self.__toggle_feature_cb, "versioning_automatic" - ) - self.switch_versioning_patterns.connect( - "state-set", self.__toggle_feature_cb, "versioning_exclusion_patterns" - ) self.switch_vmtouch.connect("state-set", self.__toggle_feature_cb, "vmtouch") self.combo_runner.connect("notify::selected", self.__set_runner) self.combo_dxvk.connect("notify::selected", self.__set_dxvk) @@ -419,11 +402,6 @@ def set_config(self, config: BottleConfig): self.switch_gamescope.handler_block_by_func(self.__toggle_feature_cb) self.switch_sandbox.handler_block_by_func(self.__toggle_feature_cb) self.switch_discrete.handler_block_by_func(self.__toggle_feature_cb) - self.switch_versioning_compression.handler_block_by_func( - self.__toggle_versioning_compression - ) - self.switch_auto_versioning.handler_block_by_func(self.__toggle_feature_cb) - self.switch_versioning_patterns.handler_block_by_func(self.__toggle_feature_cb) with contextlib.suppress(TypeError): self.switch_steam_runtime.handler_block_by_func(self.__toggle_feature_cb) self.combo_runner.handler_block_by_func(self.__set_runner) @@ -441,11 +419,6 @@ def set_config(self, config: BottleConfig): self.switch_gamemode.set_active(parameters.gamemode) self.switch_gamescope.set_active(parameters.gamescope) self.switch_sandbox.set_active(parameters.sandbox) - self.switch_versioning_compression.set_active(parameters.versioning_compression) - self.switch_auto_versioning.set_active(parameters.versioning_automatic) - self.switch_versioning_patterns.set_active( - parameters.versioning_exclusion_patterns - ) self.switch_steam_runtime.set_active(parameters.use_steam_runtime) self.switch_vmtouch.set_active(parameters.vmtouch) @@ -553,13 +526,6 @@ def set_config(self, config: BottleConfig): self.switch_gamescope.handler_unblock_by_func(self.__toggle_feature_cb) self.switch_sandbox.handler_unblock_by_func(self.__toggle_feature_cb) self.switch_discrete.handler_unblock_by_func(self.__toggle_feature_cb) - self.switch_versioning_compression.handler_unblock_by_func( - self.__toggle_versioning_compression - ) - self.switch_auto_versioning.handler_unblock_by_func(self.__toggle_feature_cb) - self.switch_versioning_patterns.handler_unblock_by_func( - self.__toggle_feature_cb - ) with contextlib.suppress(TypeError): self.switch_steam_runtime.handler_unblock_by_func(self.__toggle_feature_cb) self.combo_runner.handler_unblock_by_func(self.__set_runner) @@ -644,26 +610,7 @@ def update(): scope="Parameters", ).data["config"] - def handle_response(_widget, response_id): - if response_id == "ok": - RunAsync( - self.manager.versioning_manager.re_initialize, config=self.config - ) - _widget.destroy() - - if self.manager.versioning_manager.is_initialized(self.config): - dialog = Adw.MessageDialog.new( - self.window, - _("Are you sure you want to delete all snapshots?"), - _("This will delete all snapshots but keep your files."), - ) - dialog.add_response("cancel", _("_Cancel")) - dialog.add_response("ok", _("_Delete")) - dialog.set_response_appearance("ok", Adw.ResponseAppearance.DESTRUCTIVE) - dialog.connect("response", handle_response) - dialog.present() - else: - update() + update() def __set_runner(self, *_args): """Set the runner to use for the bottle""" diff --git a/bottles/frontend/details_versioning_page.py b/bottles/frontend/details_versioning_page.py deleted file mode 100644 index d83408f3287..00000000000 --- a/bottles/frontend/details_versioning_page.py +++ /dev/null @@ -1,161 +0,0 @@ -# details_versioning_page.py -# -# Copyright 2025 The Bottles Contributors -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, in version 3 of the License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# - -import re -from gettext import gettext as _ - -from gi.repository import Gtk, GLib, Adw - -from bottles.backend.models.result import Result -from bottles.backend.utils.threading import RunAsync -from bottles.frontend.common import open_doc_url -from bottles.frontend.gtk import GtkUtils -from bottles.frontend.state_row import StateRow - - -@Gtk.Template(resource_path="/com/usebottles/bottles/details-versioning-page.ui") -class DetailsVersioningPage(Adw.PreferencesPage): - __gtype_name__ = "DetailsVersioningPage" - __registry = [] - - # region Widgets - list_states = Gtk.Template.Child() - actions = Gtk.Template.Child() - pop_state = Gtk.Template.Child() - btn_save = Gtk.Template.Child() - btn_help = Gtk.Template.Child() - entry_state_message = Gtk.Template.Child() - status_page = Gtk.Template.Child() - pref_page = Gtk.Template.Child() - btn_add = Gtk.Template.Child() - ev_controller = Gtk.EventControllerKey.new() - - # endregion - - def __init__(self, details, config, **kwargs): - super().__init__(**kwargs) - - # common variables and references - self.window = details.window - self.manager = details.window.manager - self.versioning_manager = details.window.manager.versioning_manager - self.config = config - - self.ev_controller.connect("key-released", self.check_entry_state_message) - self.entry_state_message.add_controller(self.ev_controller) - - self.btn_save.connect("clicked", self.add_state) - self.btn_help.connect("clicked", open_doc_url, "bottles/versioning") - self.entry_state_message.connect("activate", self.add_state) - - def empty_list(self): - for r in self.__registry: - if r.get_parent() is not None: - r.get_parent().remove(r) - self.__registry = [] - - @GtkUtils.run_in_main_loop - def update(self, widget=None, config=None, states=None, active=0): - """ - This function update the states list with the - ones from the bottle configuration. - """ - if config is None: - config = self.config - if states is None: - states = self.versioning_manager.list_states(config) - if not config.Versioning: - active = states.data.get("state_id") - states = states.data.get("states") - - self.config = config - self.list_states.set_sensitive(False) - - if self.config.Versioning: - self.btn_add.set_sensitive(False) - self.btn_add.set_tooltip_text( - _("Please migrate to the new Versioning system to create new states.") - ) - - def new_state(_state, active): - entry = StateRow( - parent=self, config=self.config, state=_state, active=active - ) - self.__registry.append(entry) - self.list_states.append(entry) - - def callback(result, error=False): - self.status_page.set_visible(not result.status) - self.pref_page.set_visible(result.status) - self.list_states.set_visible(result.status) - self.list_states.set_sensitive(result.status) - - def process_states(): - GLib.idle_add(self.empty_list) - - if len(states) == 0: - return Result(False) - - for state in states.items(): - _active = int(state[0]) == int(active) - GLib.idle_add(new_state, state, _active) - - return Result(True) - - RunAsync(process_states, callback) - - def check_entry_state_message(self, *_args): - """ - This function check if the entry state message is valid, - looking for special characters. It also toggles the widget icon - and the save button sensitivity according to the result. - """ - regex = re.compile('[@!#$%^&*()<>?/|}{~:.;,"]') - message = self.entry_state_message.get_text() - check = regex.search(message) is None - - self.btn_save.set_sensitive(check) - self.entry_state_message.set_icon_from_icon_name( - 1, "" if check else 'dialog-warning-symbolic"' - ) - - def add_state(self, widget): - """ - This function create ask the versioning manager to - create a new bottle state with the given message. - """ - if not self.btn_save.get_sensitive(): - return - - @GtkUtils.run_in_main_loop - def update(result, error): - self.window.show_toast(result.message) - if result.ok: - self.update( - states=result.data.get("states"), active=result.data.get("state_id") - ) - - message = self.entry_state_message.get_text() - if message != "": - RunAsync( - task_func=self.versioning_manager.create_state, - callback=update, - config=self.config, - message=message, - ) - self.entry_state_message.set_text("") - self.pop_state.popdown() diff --git a/bottles/frontend/exclusion-pattern-row.blp b/bottles/frontend/exclusion-pattern-row.blp deleted file mode 100644 index 7965fd65882..00000000000 --- a/bottles/frontend/exclusion-pattern-row.blp +++ /dev/null @@ -1,15 +0,0 @@ -using Gtk 4.0; -using Adw 1; - -template $ExclusionPatternRow: Adw.ActionRow { - title: _("Value"); - - Button btn_remove { - valign: center; - icon-name: "user-trash-symbolic"; - - styles [ - "flat", - ] - } -} diff --git a/bottles/frontend/exclusion-patterns-dialog.blp b/bottles/frontend/exclusion-patterns-dialog.blp deleted file mode 100644 index 06f12c1a090..00000000000 --- a/bottles/frontend/exclusion-patterns-dialog.blp +++ /dev/null @@ -1,40 +0,0 @@ -using Gtk 4.0; -using Adw 1; - -template $ExclusionPatternsDialog: Adw.Window { - modal: true; - default-width: 500; - default-height: 500; - - ShortcutController { - Shortcut { - trigger: "Escape"; - action: "action(window.close)"; - } - } - - Box { - orientation: vertical; - - Adw.HeaderBar { - title-widget: Adw.WindowTitle { - title: _("Exclusion Patterns"); - }; - } - - Adw.PreferencesPage { - Adw.PreferencesGroup { - description: _("Define patterns that will be used to prevent some directories to being versioned."); - - Adw.EntryRow entry_name { - title: _("Pattern"); - show-apply-button: true; - } - } - - Adw.PreferencesGroup group_patterns { - title: _("Existing Patterns"); - } - } - } -} diff --git a/bottles/frontend/exclusion_patterns_dialog.py b/bottles/frontend/exclusion_patterns_dialog.py deleted file mode 100644 index e406a8c954a..00000000000 --- a/bottles/frontend/exclusion_patterns_dialog.py +++ /dev/null @@ -1,111 +0,0 @@ -# exclusion_patterns_dialog.py -# -# Copyright 2025 The Bottles Contributors -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, in version 3 of the License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# - -from gettext import gettext as _ - -from gi.repository import Gtk, GLib, Adw - - -@Gtk.Template(resource_path="/com/usebottles/bottles/exclusion-pattern-row.ui") -class ExclusionPatternRow(Adw.ActionRow): - __gtype_name__ = "ExclusionPatternRow" - - # region Widgets - btn_remove = Gtk.Template.Child() - # endregion - - def __init__(self, parent, pattern, **kwargs): - super().__init__(**kwargs) - - # common variables and references - self.parent = parent - self.manager = parent.window.manager - self.config = parent.config - self.pattern = pattern - - self.set_title(self.pattern) - - # connect signals - self.btn_remove.connect("clicked", self.__remove) - - def __remove(self, *_args): - """ - Remove the env var from the bottle configuration and - destroy the widget - """ - patterns = self.config.Versioning_Exclusion_Patterns - if self.pattern in patterns: - patterns.remove(self.pattern) - - self.manager.update_config( - config=self.config, key="Versioning_Exclusion_Patterns", value=patterns - ) - self.parent.group_patterns.remove(self) - - -@Gtk.Template(resource_path="/com/usebottles/bottles/exclusion-patterns-dialog.ui") -class ExclusionPatternsDialog(Adw.Window): - __gtype_name__ = "ExclusionPatternsDialog" - - # region Widgets - entry_name = Gtk.Template.Child() - group_patterns = Gtk.Template.Child() - # endregion - - def __init__(self, window, config, **kwargs): - super().__init__(**kwargs) - self.set_transient_for(window) - - # common variables and references - self.window = window - self.manager = window.manager - self.config = config - - self.__populate_patterns_list() - - # connect signals - self.entry_name.connect("apply", self.__save_var) - - def __save_var(self, *_args): - """ - This function save the new env var to the - bottle configuration - """ - pattern = self.entry_name.get_text() - self.manager.update_config( - config=self.config, - key="Versioning_Exclusion_Patterns", - value=self.config.Versioning_Exclusion_Patterns + [pattern], - ) - _entry = ExclusionPatternRow(self, pattern) - GLib.idle_add(self.group_patterns.add, _entry) - self.entry_name.set_text("") - - def __populate_patterns_list(self): - """ - This function populate the list of exclusion patterns - with the existing ones from the bottle configuration - """ - patterns = self.config.Versioning_Exclusion_Patterns - if len(patterns) == 0: - self.group_patterns.set_description(_("No exclusion patterns defined.")) - return - - self.group_patterns.set_description("") - for pattern in patterns: - _entry = ExclusionPatternRow(self, pattern) - GLib.idle_add(self.group_patterns.add, _entry) diff --git a/bottles/frontend/meson.build b/bottles/frontend/meson.build index 7372cfd3456..bab61821996 100644 --- a/bottles/frontend/meson.build +++ b/bottles/frontend/meson.build @@ -17,7 +17,6 @@ blueprints = custom_target('blueprints', 'details-dependencies-view.blp', 'details-installers-view.blp', 'details-task-manager-view.blp', - 'details-versioning-page.blp', 'bottle-details-view.blp', 'bottle-picker-dialog.blp', 'crash-report-dialog.blp', @@ -26,7 +25,6 @@ blueprints = custom_target('blueprints', 'drives-dialog.blp', 'duplicate-dialog.blp', 'environment-variables-dialog.blp', - 'exclusion-patterns-dialog.blp', 'gamescope-dialog.blp', 'installer-dialog.blp', 'journal-dialog.blp', @@ -34,7 +32,6 @@ blueprints = custom_target('blueprints', 'proton-alert-dialog.blp', 'rename-program-dialog.blp', 'sandbox-dialog.blp', - 'upgrade-versioning-dialog.blp', 'vkbasalt-dialog.blp', 'display-dialog.blp', 'vmtouch-dialog.blp', @@ -43,7 +40,6 @@ blueprints = custom_target('blueprints', 'dll-override-entry.blp', 'drive-entry.blp', 'env-var-entry.blp', - 'exclusion-pattern-row.blp', 'importer-row.blp', 'importer-view.blp', 'installer-row.blp', @@ -57,7 +53,6 @@ blueprints = custom_target('blueprints', 'onboard-dialog.blp', 'preferences.blp', 'program-row.blp', - 'state-row.blp', 'task-row.blp', 'window.blp', 'details-preferences-page.blp', @@ -108,14 +103,12 @@ bottles_sources = [ 'details_installers_view.py', 'details_dependencies_view.py', 'details_preferences_page.py', - 'details_versioning_page.py', 'details_task_manager_view.py', 'dependency_entry_row.py', 'executable.py', 'importer_row.py', 'installer_row.py', 'program_row.py', - 'state_row.py', 'component_entry_row.py', 'library_entry.py', 'crash_report_dialog.py', @@ -139,8 +132,6 @@ bottles_sources = [ 'sandbox_dialog.py', 'installer_dialog.py', 'dependencies_check_dialog.py', - 'exclusion_patterns_dialog.py', - 'upgrade_versioning_dialog.py', 'vmtouch_dialog.py', 'window.py', params_file, diff --git a/bottles/frontend/state-row.blp b/bottles/frontend/state-row.blp deleted file mode 100644 index 8358e50282e..00000000000 --- a/bottles/frontend/state-row.blp +++ /dev/null @@ -1,24 +0,0 @@ -using Gtk 4.0; -using Adw 1; - -template $StateRow: Adw.ActionRow { - activatable-widget: btn_restore; - - /* Translators: id as identification */ - title: _("State id"); - subtitle: _("State comment"); - - Spinner spinner { - visible: false; - } - - Button btn_restore { - tooltip-text: _("Restore this Snapshot"); - valign: center; - icon-name: "document-open-recent-symbolic"; - - styles [ - "flat", - ] - } -} diff --git a/bottles/frontend/state_row.py b/bottles/frontend/state_row.py deleted file mode 100644 index 35e1f654a33..00000000000 --- a/bottles/frontend/state_row.py +++ /dev/null @@ -1,128 +0,0 @@ -# state_row.py -# -# Copyright 2025 The Bottles Contributors -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, in version 3 of the License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# - -from datetime import datetime -from gettext import gettext as _ - -from gi.repository import Gtk, Adw - -from bottles.backend.utils.threading import RunAsync -from bottles.frontend.gtk import GtkUtils - - -@Gtk.Template(resource_path="/com/usebottles/bottles/state-row.ui") -class StateRow(Adw.ActionRow): - __gtype_name__ = "StateRow" - - # region Widgets - btn_restore = Gtk.Template.Child() - spinner = Gtk.Template.Child() - - # endregion - - def __init__(self, parent, config, state, active, **kwargs): - super().__init__(**kwargs) - - # common variables and references - self.parent = parent - self.window = parent.window - self.manager = parent.window.manager - self.queue = parent.window.page_details.queue - self.state = state - - if config.Versioning: - self.state_name = "#{} - {}".format( - state[0], - datetime.strptime( - state[1]["Creation_Date"], "%Y-%m-%d %H:%M:%S.%f" - ).strftime("%d %B %Y, %H:%M"), - ) - - self.set_subtitle(self.state[1]["Comment"]) - if state[0] == config.State: - self.add_css_class("current-state") - else: - self.state_name = "{} - {}".format( - state[0], - datetime.fromtimestamp(state[1]["timestamp"]).strftime( - "%d %B %Y, %H:%M" - ), - ) - self.set_subtitle(state[1]["message"]) - if active: - self.add_css_class("current-state") - - self.set_title(self.state_name) - self.config = config - self.versioning_manager = self.manager.versioning_manager - - # connect signals - self.btn_restore.connect("clicked", self.set_state) - - def set_state(self, widget): - """ - Set the bottle state to this one. - """ - - def handle_response(dialog, response_id): - if response_id == "ok": - self.queue.add_task() - self.parent.set_sensitive(False) - self.spinner.show() - self.spinner.start() - - def _after(): - self.window.page_details.view_versioning.update(None, self.config) - self.manager.update_bottles() - - RunAsync( - task_func=self.versioning_manager.set_state, - callback=self.set_completed, - config=self.config, - state_id=self.state[0], - after=_after, - ) - dialog.destroy() - - dialog = Adw.MessageDialog.new( - self.window, - _("Are you sure you want to restore this state?"), - _( - "Restoring this state will overwrite the current configuration and cannot be undone." - ), - ) - dialog.add_response("cancel", _("_Cancel")) - dialog.add_response("ok", _("_Restore")) - dialog.set_response_appearance("ok", Adw.ResponseAppearance.SUGGESTED) - dialog.connect("response", handle_response) - dialog.present() - - @GtkUtils.run_in_main_loop - def set_completed(self, result, error=False): - """ - Set completed status to the widget. - """ - if not self.config.Versioning and result.message: - self.window.show_toast(result.message) - self.spinner.stop() - self.spinner.hide() - self.btn_restore.set_visible(False) - self.parent.set_sensitive(True) - self.queue.end_task() - self.manager.update_bottles() - config = self.manager.local_bottles[self.config.Path] - self.window.page_details.set_config(config) diff --git a/bottles/frontend/upgrade-versioning-dialog.blp b/bottles/frontend/upgrade-versioning-dialog.blp deleted file mode 100644 index 2b4909ab07c..00000000000 --- a/bottles/frontend/upgrade-versioning-dialog.blp +++ /dev/null @@ -1,131 +0,0 @@ -using Gtk 4.0; -using Adw 1; - -template $UpgradeVersioningDialog: Adw.Window { - modal: true; - default-width: 500; - default-height: 400; - destroy-with-parent: true; - - Box { - orientation: vertical; - - Adw.HeaderBar { - show-end-title-buttons: false; - - title-widget: Adw.WindowTitle { - title: _("Upgrade Needed"); - }; - - Button btn_cancel { - label: _("_Cancel"); - use-underline: true; - action-name: "window.close"; - } - - ShortcutController { - scope: managed; - - Shortcut { - trigger: "Escape"; - action: "action(window.close)"; - } - } - - [end] - Button btn_proceed { - label: _("Continue"); - - styles [ - "suggested-action", - ] - } - - [end] - Button btn_upgrade { - label: _("Launch upgrade"); - visible: false; - - styles [ - "suggested-action", - ] - } - - styles [ - "flat", - ] - } - - Stack stack_switcher { - StackPage { - name: "page_status"; - - child: Adw.StatusPage status_page { - icon-name: "preferences-system-time-symbolic"; - title: _("New Versioning System"); - vexpand: true; - hexpand: true; - description: _("The new bottle versioning system has landed."); - }; - } - - StackPage { - name: "page_info"; - - child: Label { - margin-top: 10; - margin-start: 10; - margin-end: 10; - wrap: true; - label: _("Bottles has a whole new Versioning System that is not backwards compatible.\n\nTo continue using versioning we need to re-initialize the bottle repository. This will not delete data from your bottle but will delete all existing snapshots and create a new one.\n\nIf you need to go back to a previous snapshot before continuing, close this window and restore the snapshot, then reopen the bottle to show this window again.\n\nThe old system will be discontinued in one of the next releases."); - }; - } - - StackPage { - name: "page_upgrading"; - - child: Box page_upgrading { - margin-top: 24; - margin-bottom: 24; - orientation: vertical; - vexpand: true; - hexpand: true; - - Label { - halign: center; - margin-top: 12; - margin-bottom: 12; - label: _("Re-initializing Repository…"); - - styles [ - "title-1", - ] - } - - Label { - margin-bottom: 6; - label: _("This could take a while."); - } - - ProgressBar progressbar { - width-request: 300; - halign: center; - margin-top: 24; - margin-bottom: 12; - } - }; - } - - StackPage { - name: "page_finish"; - - child: Adw.StatusPage page_finish { - vexpand: true; - hexpand: true; - icon-name: "object-select-symbolic"; - title: _("Done! Please restart Bottles."); - }; - } - } - } -} diff --git a/bottles/frontend/upgrade_versioning_dialog.py b/bottles/frontend/upgrade_versioning_dialog.py deleted file mode 100644 index cb5b2d8d34c..00000000000 --- a/bottles/frontend/upgrade_versioning_dialog.py +++ /dev/null @@ -1,81 +0,0 @@ -# upgrade_versioning_dialog.py -# -# Copyright 2025 The Bottles Contributors -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, in version 3 of the License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# - -import time -from gi.repository import Gtk, Adw - -from bottles.backend.utils.threading import RunAsync - - -@Gtk.Template(resource_path="/com/usebottles/bottles/upgrade-versioning-dialog.ui") -class UpgradeVersioningDialog(Adw.Window): - __gtype_name__ = "UpgradeVersioningDialog" - - # region Widgets - btn_cancel = Gtk.Template.Child() - btn_proceed = Gtk.Template.Child() - btn_upgrade = Gtk.Template.Child() - stack_switcher = Gtk.Template.Child() - progressbar = Gtk.Template.Child() - - # endregion - - def __init__(self, parent, **kwargs): - super().__init__(**kwargs) - self.set_transient_for(parent.window) - - # common variables and references - self.parent = parent - self.config = parent.config - - # connect signals - self.btn_upgrade.connect("clicked", self.__upgrade) - self.btn_proceed.connect("clicked", self.__proceed) - - def __upgrade(self, widget): - """ - This function take the new bottle name from the entry - and create a new duplicate of the bottle. It also change the - stack_switcher page when the process is finished. - """ - self.stack_switcher.set_visible_child_name("page_upgrading") - self.btn_upgrade.set_visible(False) - self.btn_cancel.set_visible(False) - self.btn_cancel.set_label("Close") - - RunAsync(self.pulse) - RunAsync( - self.parent.manager.versioning_manager.update_system, - self.finish, - self.config, - ) - - def __proceed(self, widget): - self.stack_switcher.set_visible_child_name("page_info") - self.btn_proceed.set_visible(False) - self.btn_upgrade.set_visible(True) - - def finish(self, result, error=False): - self.btn_cancel.set_visible(True) - self.parent.manager.update_bottles() - self.stack_switcher.set_visible_child_name("page_finish") - - def pulse(self): - # This function update the progress bar every half second. - while True: - time.sleep(0.5) - self.progressbar.pulse() From f4567107ddfb4650d316e9e2f4e8fc76c4002e81 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Tue, 21 Jan 2025 22:40:00 -0500 Subject: [PATCH 101/146] backend: Remove versioning --- bottles/backend/managers/dependency.py | 10 - bottles/backend/managers/manager.py | 9 - bottles/backend/managers/meson.build | 1 - bottles/backend/managers/versioning.py | 278 ------------------------- 4 files changed, 298 deletions(-) delete mode 100644 bottles/backend/managers/versioning.py diff --git a/bottles/backend/managers/dependency.py b/bottles/backend/managers/dependency.py index 02217b3d123..fd3eb3359e4 100644 --- a/bottles/backend/managers/dependency.py +++ b/bottles/backend/managers/dependency.py @@ -78,16 +78,6 @@ def install(self, config: BottleConfig, dependency: list) -> Result: """ uninstaller = True - if config.Parameters.versioning_automatic: - """ - If the bottle has the versioning system enabled, we need - to create a new version of the bottle, before installing - the dependency. - """ - self.__manager.versioning_manager.create_state( - config=config, message=f"Before installing {dependency[0]}" - ) - task_id = TaskManager.add(Task(title=dependency[0])) logging.info( diff --git a/bottles/backend/managers/manager.py b/bottles/backend/managers/manager.py index d77d29b7411..c0c74eb041d 100644 --- a/bottles/backend/managers/manager.py +++ b/bottles/backend/managers/manager.py @@ -46,7 +46,6 @@ from bottles.backend.managers.steam import SteamManager from bottles.backend.managers.template import TemplateManager from bottles.backend.managers.ubisoftconnect import UbisoftConnectManager -from bottles.backend.managers.versioning import VersioningManager from bottles.backend.models.config import BottleConfig from bottles.backend.models.result import Result from bottles.backend.models.samples import Samples @@ -126,8 +125,6 @@ def __init__( ) # sub-managers - self.versioning_manager = VersioningManager(self) - times["VersioningManager"] = time.time() self.component_manager = ComponentManager(self) self.installer_manager = InstallerManager(self) self.dependency_manager = DependencyManager(self) @@ -1336,12 +1333,6 @@ def components_check(): # save bottle config config.dump(f"{bottle_complete_path}/bottle.yml") - if versioning: - # create first state if versioning enabled - logging.info("Creating versioning state 0…") - log_update(_("Creating versioning state 0…")) - self.versioning_manager.create_state(config=config, message="First boot") - # set status created and UI usability logging.info(f"New bottle created: {bottle_name}", jn=True) log_update(_("Finalizing…")) diff --git a/bottles/backend/managers/meson.build b/bottles/backend/managers/meson.build index 1829d283956..35dbb180370 100644 --- a/bottles/backend/managers/meson.build +++ b/bottles/backend/managers/meson.build @@ -9,7 +9,6 @@ bottles_sources = [ 'installer.py', 'library.py', 'manager.py', - 'versioning.py', 'data.py', 'runtime.py', 'importer.py', diff --git a/bottles/backend/managers/versioning.py b/bottles/backend/managers/versioning.py deleted file mode 100644 index 6f5163a1519..00000000000 --- a/bottles/backend/managers/versioning.py +++ /dev/null @@ -1,278 +0,0 @@ -# versioning.py -# -# Copyright 2022 brombinmirko -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, in version 3 of the License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# - -import os -import shutil -from datetime import datetime -from gettext import gettext as _ -from glob import glob - -from typing import Any - -from fvs.exceptions import ( # type: ignore [import-untyped] - FVSNothingToCommit, - FVSStateNotFound, - FVSNothingToRestore, - FVSStateZeroNotDeletable, -) -from fvs.repo import FVSRepo # type: ignore [import-untyped] - -from bottles.backend.logger import Logger -from bottles.backend.models.config import BottleConfig -from bottles.backend.models.result import Result -from bottles.backend.state import TaskManager, Task -from bottles.backend.utils import yaml -from bottles.backend.utils.file import FileUtils -from bottles.backend.utils.manager import ManagerUtils - -logging = Logger() - - -# noinspection PyTypeChecker -class VersioningManager: - def __init__(self, manager): - self.manager = manager - - @staticmethod - def __get_patterns(config: BottleConfig): - patterns = ["*dosdevices*", "*cache*"] - if config.Parameters.versioning_exclusion_patterns: - patterns += config.Versioning_Exclusion_Patterns - return patterns - - @staticmethod - def is_initialized(config: BottleConfig): - try: - repo = FVSRepo( - repo_path=ManagerUtils.get_bottle_path(config), - use_compression=config.Parameters.versioning_compression, - no_init=True, - ) - except FileNotFoundError: - return False - return not repo.has_no_states - - @staticmethod - def re_initialize(config: BottleConfig): - fvs_path = os.path.join(ManagerUtils.get_bottle_path(config), ".fvs") - if os.path.exists(fvs_path): - shutil.rmtree(fvs_path) - - def update_system(self, config: BottleConfig): - states_path = os.path.join(ManagerUtils.get_bottle_path(config), "states") - if os.path.exists(states_path): - shutil.rmtree(states_path) - return self.manager.update_config(config, "Versioning", False) - - def create_state(self, config: BottleConfig, message: str = "No message"): - patterns = self.__get_patterns(config) - repo = FVSRepo( - repo_path=ManagerUtils.get_bottle_path(config), - use_compression=config.Parameters.versioning_compression, - ) - task_id = TaskManager.add(Task(title=_("Committing state …"))) - try: - repo.commit(message, ignore=patterns) - except FVSNothingToCommit: - TaskManager.remove(task_id) - return Result(status=False, message=_("Nothing to commit")) - - TaskManager.remove(task_id) - return Result( - status=True, - message=_("New state [{0}] created successfully!").format( - repo.active_state_id - ), - data={"state_id": repo.active_state_id, "states": repo.states}, - ) - - def list_states( - self, config: BottleConfig - ) -> dict[str, Any] | Result[dict[str, Any]]: - """ - This function take all the states from the states.yml file - of the given bottle and return them as a dict. - """ - if not config.Versioning: - try: - repo = FVSRepo( - repo_path=ManagerUtils.get_bottle_path(config), - use_compression=config.Parameters.versioning_compression, - ) - except FVSStateNotFound: - logging.warning( - "The FVS repository may be corrupted, trying to re-initialize it" - ) - self.re_initialize(config) - repo = FVSRepo( - repo_path=ManagerUtils.get_bottle_path(config), - use_compression=config.Parameters.versioning_compression, - ) - return Result( - status=True, - message=_("States list retrieved successfully!"), - data={"state_id": repo.active_state_id, "states": repo.states}, - ) - - bottle_path = ManagerUtils.get_bottle_path(config) - states = {} - - try: - states_file = open("%s/states/states.yml" % bottle_path) - states_file_yaml = yaml.load(states_file) - states_file.close() - states = states_file_yaml.get("States") - logging.info(f"Found [{len(states)}] states for bottle: [{config.Name}]") - except (FileNotFoundError, yaml.YAMLError): - logging.info(f"No states found for bottle: [{config.Name}]") - - return states - - def set_state( - self, config: BottleConfig, state_id: int, after: callable = None - ) -> Result: - if not config.Versioning: - patterns = self.__get_patterns(config) - repo = FVSRepo( - repo_path=ManagerUtils.get_bottle_path(config), - use_compression=config.Parameters.versioning_compression, - ) - res = Result( - status=True, - message=_("State {0} restored successfully!").format(state_id), - ) - task_id = TaskManager.add(Task(title=_(f"Restoring state {state_id} …"))) - try: - repo.restore_state(state_id, ignore=patterns) - except FVSStateNotFound: - logging.error(f"State {state_id} not found.") - res = Result(status=False, message=_("State not found")) - except (FVSNothingToRestore, FVSStateZeroNotDeletable): - logging.error(f"State {state_id} is the active state.") - res = Result( - status=False, - message=_("State {} is already the active state").format(state_id), - ) - TaskManager.remove(task_id) - return res - - bottle_path = ManagerUtils.get_bottle_path(config) - logging.info(f"Restoring to state: [{state_id}]") - - # get bottle and state indexes - bottle_index = self.get_index(config) - state_index = self.get_state_files(config, state_id) - - search_sources = list(range(int(state_id) + 1)) - search_sources.reverse() - - # check for removed and changed files - remove_files = [] - edit_files = [] - for file in bottle_index.get("Files"): - if file["file"] not in [f["file"] for f in state_index.get("Files")]: - remove_files.append(file) - elif file["checksum"] not in [ - f["checksum"] for f in state_index.get("Files") - ]: - edit_files.append(file) - logging.info(f"[{len(remove_files)}] files to remove.") - logging.info(f"[{len(edit_files)}] files to replace.") - - # check for new files - add_files = [] - for file in state_index.get("Files"): - if file["file"] not in [f["file"] for f in bottle_index.get("Files")]: - add_files.append(file) - logging.info(f"[{len(add_files)}] files to add.") - - # perform file updates - for file in remove_files: - os.remove("{}/drive_c/{}".format(bottle_path, file["file"])) - - for file in add_files: - source = "{}/states/{}/drive_c/{}".format( - bottle_path, - str(state_id), - file["file"], - ) - target = "{}/drive_c/{}".format(bottle_path, file["file"]) - shutil.copy2(source, target) - - for file in edit_files: - for i in search_sources: - source = "{}/states/{}/drive_c/{}".format( - bottle_path, str(i), file["file"] - ) - if os.path.isfile(source): - checksum = FileUtils().get_checksum(source) - if file["checksum"] == checksum: - break - target = "{}/drive_c/{}".format(bottle_path, file["file"]) - shutil.copy2(source, target) - - # update State in bottle config - self.manager.update_config(config, "State", state_id) - - # execute caller function after all - if after: - after() - - return Result(True) - - @staticmethod - def get_state_files( - config: BottleConfig, state_id: int, plain: bool = False - ) -> str | Any: - """ - Return the files.yml content of the state. Use the plain argument - to return the content as plain text. - """ - try: - file = open( - "%s/states/%s/files.yml" - % (ManagerUtils.get_bottle_path(config), state_id) - ) - files = file.read() if plain else yaml.load(file.read()) - file.close() - return files - except (OSError, yaml.YAMLError): - logging.error("Could not read the state files file.") - return {} - - @staticmethod - def get_index(config: BottleConfig): - """List all files in a bottle and return as dict.""" - bottle_path = ManagerUtils.get_bottle_path(config) - cur_index = {"Update_Date": str(datetime.now()), "Files": []} - for file in glob("%s/drive_c/**" % bottle_path, recursive=True): - if not os.path.isfile(file): - continue - - if os.path.islink(os.path.dirname(file)): - continue - - if file[len(bottle_path) + 9 :].split("/")[0] in ["users"]: - continue - - cur_index["Files"].append( - { - "file": file[len(bottle_path) + 9 :], - "checksum": FileUtils().get_checksum(file), - } - ) - return cur_index From 0c25ed5844b3e66c8fc53d433fa944406063ee2b Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Tue, 21 Jan 2025 23:01:20 -0500 Subject: [PATCH 102/146] frontend: Remove SteamManager --- bottles/frontend/bottles-list-view.blp | 12 ------------ bottles/frontend/bottles_list_view.py | 18 +----------------- bottles/frontend/program_row.py | 23 ----------------------- 3 files changed, 1 insertion(+), 52 deletions(-) diff --git a/bottles/frontend/bottles-list-view.blp b/bottles/frontend/bottles-list-view.blp index 299ca52141d..baead640520 100644 --- a/bottles/frontend/bottles-list-view.blp +++ b/bottles/frontend/bottles-list-view.blp @@ -24,18 +24,6 @@ template $BottlesListView: Adw.Bin { ] } } - - Adw.PreferencesGroup group_steam { - title: _("Steam Proton"); - - ListBox list_steam { - selection-mode: none; - - styles [ - "boxed-list", - ] - } - } } Adw.StatusPage bottle_status { diff --git a/bottles/frontend/bottles_list_view.py b/bottles/frontend/bottles_list_view.py index 5c5d04d3a5c..6b960392e8c 100644 --- a/bottles/frontend/bottles_list_view.py +++ b/bottles/frontend/bottles_list_view.py @@ -130,9 +130,7 @@ class BottlesListView(Adw.Bin): # region Widgets list_bottles = Gtk.Template.Child() - list_steam = Gtk.Template.Child() group_bottles = Gtk.Template.Child() - group_steam = Gtk.Template.Child() pref_page = Gtk.Template.Child() bottle_status = Gtk.Template.Child() btn_create = Gtk.Template.Child() @@ -168,7 +166,6 @@ def __search_bottles(self, widget, event=None, data=None): """ terms = widget.get_text() self.list_bottles.set_filter_func(self.__filter_bottles, terms) - self.list_steam.set_filter_func(self.__filter_bottles, terms) @staticmethod def __filter_bottles(row, terms=None): @@ -180,9 +177,6 @@ def update_bottles_list(self, *args) -> None: while self.list_bottles.get_first_child(): self.list_bottles.remove(self.list_bottles.get_first_child()) - while self.list_steam.get_first_child(): - self.list_steam.remove(self.list_steam.get_first_child()) - local_bottles = self.window.manager.local_bottles is_empty_local_bottles = len(local_bottles) == 0 @@ -193,17 +187,7 @@ def update_bottles_list(self, *args) -> None: _entry = BottleRow(self.window, config) self.__bottles[config.Path] = _entry - if config.Environment != "Steam": - self.list_bottles.append(_entry) - else: - self.list_steam.append(_entry) - - if self.list_steam.get_first_child() is None: - self.group_steam.set_visible(False) - self.group_bottles.set_title("") - else: - self.group_steam.set_visible(True) - self.group_bottles.set_title(_("Your Bottles")) + self.list_bottles.append(_entry) def show_page(self, page: str) -> None: if config := self.window.manager.local_bottles.get(page): diff --git a/bottles/frontend/program_row.py b/bottles/frontend/program_row.py index d73f272608c..7a75a25f486 100644 --- a/bottles/frontend/program_row.py +++ b/bottles/frontend/program_row.py @@ -21,7 +21,6 @@ from gi.repository import Gtk, Adw from bottles.backend.managers.library import LibraryManager -from bottles.backend.managers.steam import SteamManager from bottles.backend.models.result import Result from bottles.backend.utils.manager import ManagerUtils from bottles.backend.utils.threading import RunAsync @@ -117,7 +116,6 @@ def __init__( self.btn_browse.connect("clicked", self.browse_program_folder) self.btn_add_entry.connect("clicked", self.add_entry) self.btn_add_library.connect("clicked", self.add_to_library) - self.btn_add_steam.connect("clicked", self.add_to_steam) self.btn_remove.connect("clicked", self.remove_program) if not program.get("removed") and not is_steam and check_boot: @@ -332,24 +330,3 @@ def add_to_library(): self.btn_add_library.set_visible(False) RunAsync(add_to_library, update) - - def add_to_steam(self, _widget): - def update(result, _error=False): - if result.ok: - self.window.show_toast( - _('"{0}" added to your Steam library').format(self.program["name"]) - ) - else: - self.window.show_toast( - _('"{0}" failed adding to your Steam library').format( - self.program["name"] - ) - ) - - steam_manager = SteamManager(self.config) - RunAsync( - steam_manager.add_shortcut, - update, - program_name=self.program["name"], - program_path=self.program["path"], - ) From b80be0fda92f54dea237ccff71cf5cd493b9c9c3 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Tue, 21 Jan 2025 23:01:35 -0500 Subject: [PATCH 103/146] backend: Remove SteamManager --- bottles/backend/managers/manager.py | 24 -- bottles/backend/managers/meson.build | 1 - bottles/backend/managers/runtime.py | 42 -- bottles/backend/managers/steam.py | 567 --------------------------- bottles/backend/wine/winecommand.py | 33 -- bottles/frontend/library_entry.py | 5 - bottles/frontend/preferences.py | 7 - bottles/frontend/program_row.py | 23 +- 8 files changed, 1 insertion(+), 701 deletions(-) delete mode 100644 bottles/backend/managers/steam.py diff --git a/bottles/backend/managers/manager.py b/bottles/backend/managers/manager.py index c0c74eb041d..f6ab1388906 100644 --- a/bottles/backend/managers/manager.py +++ b/bottles/backend/managers/manager.py @@ -43,7 +43,6 @@ from bottles.backend.managers.importer import ImportManager from bottles.backend.managers.installer import InstallerManager from bottles.backend.managers.library import LibraryManager -from bottles.backend.managers.steam import SteamManager from bottles.backend.managers.template import TemplateManager from bottles.backend.managers.ubisoftconnect import UbisoftConnectManager from bottles.backend.models.config import BottleConfig @@ -130,8 +129,6 @@ def __init__( self.dependency_manager = DependencyManager(self) self.import_manager = ImportManager(self) times["ImportManager"] = time.time() - self.steam_manager = SteamManager() - times["SteamManager"] = time.time() times.update(self.checks(install_latest=False, first_run=True).data) @@ -644,17 +641,6 @@ def get_programs(self, config: BottleConfig) -> list[dict]: ) found.append(executable_name) - win_steam_manager = SteamManager(config, is_windows=True) - - if ( - self.settings.get_boolean("steam-programs") - and win_steam_manager.is_steam_supported - ): - programs_names = [p.get("name", "") for p in installed_programs] - for app in win_steam_manager.get_installed_apps_as_programs(): - if app["name"] not in programs_names: - installed_programs.append(app) - if self.settings.get_boolean( "epic-games" ) and EpicGamesStoreManager.is_epic_supported(config): @@ -819,13 +805,6 @@ def process_bottle(bottle): "Bottles found:\n - {}".format("\n - ".join(self.local_bottles)) ) - if ( - self.settings.get_boolean("steam-proton-support") - and self.steam_manager.is_steam_supported - ): - self.steam_manager.update_bottles() - self.local_bottles.update(self.steam_manager.list_prefixes()) - # Update parameters in bottle config def update_config( self, @@ -879,9 +858,6 @@ def update_config( config.Update_Date = str(datetime.now()) - if config.Environment == "Steam": - self.steam_manager.update_bottle(config) - return Result(status=True, data={"config": config}) def create_bottle_from_config(self, config: BottleConfig) -> bool: diff --git a/bottles/backend/managers/meson.build b/bottles/backend/managers/meson.build index 35dbb180370..ee4d29ff547 100644 --- a/bottles/backend/managers/meson.build +++ b/bottles/backend/managers/meson.build @@ -16,7 +16,6 @@ bottles_sources = [ 'journal.py', 'template.py', 'sandbox.py', - 'steam.py', 'epicgamesstore.py', 'ubisoftconnect.py', 'origin.py', diff --git a/bottles/backend/managers/runtime.py b/bottles/backend/managers/runtime.py index a56e31d992c..86b14201e64 100644 --- a/bottles/backend/managers/runtime.py +++ b/bottles/backend/managers/runtime.py @@ -27,7 +27,6 @@ class RuntimeManager: def get_runtimes(_filter: str = "bottles"): runtimes = { "bottles": RuntimeManager.__get_bottles_runtime(), - "steam": RuntimeManager.__get_steam_runtime(), } if _filter == "steam": @@ -118,44 +117,3 @@ def __get_bottles_runtime(): structure = ["lib", "lib32"] return RuntimeManager.__get_runtime(paths, structure) - - @staticmethod - def __get_steam_runtime(): - from bottles.backend.managers.steam import SteamManager - - available_runtimes = {} - steam_manager = SteamManager(check_only=True) - - if not steam_manager.is_steam_supported: - return available_runtimes - - lookup = { - "sniper": { - "name": "sniper", - "entry_point": os.path.join( - steam_manager.steam_path, - "steamapps/common/SteamLinuxRuntime_sniper/_v2-entry-point", - ), - }, - "soldier": { - "name": "soldier", - "entry_point": os.path.join( - steam_manager.steam_path, - "steamapps/common/SteamLinuxRuntime_soldier/_v2-entry-point", - ), - }, - "scout": { - "name": "scout", - "entry_point": os.path.join( - steam_manager.steam_path, "ubuntu12_32/steam-runtime/run.sh" - ), - }, - } - - for name, data in lookup.items(): - if not os.path.exists(data["entry_point"]): - continue - - available_runtimes[name] = data - - return available_runtimes diff --git a/bottles/backend/managers/steam.py b/bottles/backend/managers/steam.py deleted file mode 100644 index 495214ad52d..00000000000 --- a/bottles/backend/managers/steam.py +++ /dev/null @@ -1,567 +0,0 @@ -# steam.py -# -# Copyright 2022 brombinmirko -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, in version 3 of the License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# - -import contextlib -import os -import shlex -import shutil -import uuid -from datetime import datetime -from functools import lru_cache -from glob import glob -from pathlib import Path - -from bottles.backend.globals import Paths -from bottles.backend.models.config import BottleConfig -from bottles.backend.models.result import Result -from bottles.backend.models.samples import Samples -from bottles.backend.models.vdict import VDFDict -from bottles.backend.state import Signals, SignalManager -from bottles.backend.utils import vdf -from bottles.backend.utils.manager import ManagerUtils -from bottles.backend.utils.steam import SteamUtils -from bottles.backend.wine.winecommand import WineCommand - -from bottles.backend.logger import Logger - -logging = Logger() - - -class SteamManager: - steamapps_path = None - userdata_path = None - localconfig_path = None - localconfig = {} - library_folders = [] - - def __init__( - self, - config: BottleConfig | None = None, - is_windows: bool = False, - check_only: bool = False, - ): - self.config = config - self.is_windows = is_windows - self.steam_path = self.__find_steam_path() - self.is_steam_supported = self.steam_path is not None - if self.is_steam_supported and not check_only: - self.steamapps_path = self.__get_scoped_path("steamapps") - self.userdata_path = self.__get_scoped_path("userdata") - self.localconfig_path = self.__get_local_config_path() - self.localconfig = self.__get_local_config() - self.library_folders = self.__get_library_folders() - - def __find_steam_path(self) -> str | None: - if self.is_windows and self.config: - paths = [ - os.path.join( - ManagerUtils.get_bottle_path(self.config), - "drive_c/Program Files (x86)/Steam", - ) - ] - else: - paths = [ - os.path.join( - Path.home(), ".var/app/com.valvesoftware.Steam/data/Steam" - ), - os.path.join(Path.home(), ".local/share/Steam"), - os.path.join(Path.home(), ".steam/debian-installation"), - os.path.join(Path.home(), ".steam/steam"), - os.path.join(Path.home(), ".steam"), - ] - - for path in paths: - if os.path.isdir(path): - return path - return None - - def __get_scoped_path(self, scope: str = "steamapps"): - """scopes: steamapps, userdata""" - if scope not in ["steamapps", "userdata"]: - raise ValueError("scope must be either 'steamapps' or 'userdata'") - - path = os.path.join(self.steam_path, scope) - if os.path.isdir(path): - return path - return None - - @staticmethod - def get_acf_data(libraryfolder: str, app_id: str) -> dict | None: - acf_path = os.path.join(libraryfolder, f"steamapps/appmanifest_{app_id}.acf") - if not os.path.isfile(acf_path): - return None - - with open(acf_path, errors="replace") as f: - data = SteamUtils.parse_acf(f.read()) - - return data - - def __get_local_config_path(self) -> str | None: - if self.userdata_path is None: - return None - - confs = glob(os.path.join(self.userdata_path, "*/config/localconfig.vdf")) - if len(confs) == 0: - logging.warning("Could not find any localconfig.vdf file in Steam userdata") - return None - - return confs[0] - - def __get_library_folders(self) -> list | None: - if not self.steamapps_path: - return None - - library_folders_path = os.path.join(self.steamapps_path, "libraryfolders.vdf") - library_folders = [] - - if not os.path.exists(library_folders_path): - logging.warning("Could not find the libraryfolders.vdf file") - return None - - with open(library_folders_path, errors="replace") as f: - _library_folders = SteamUtils.parse_vdf(f.read()) - - if _library_folders is None or not _library_folders.get("libraryfolders"): - logging.warning("Could not parse libraryfolders.vdf") - return None - - for _, folder in _library_folders["libraryfolders"].items(): - if ( - not isinstance(folder, dict) - or not folder.get("path") - or not folder.get("apps") - ): - continue - - library_folders.append(folder) - - return library_folders if len(library_folders) > 0 else None - - @lru_cache - def get_appid_library_path(self, appid: str) -> str | None: - if self.library_folders is None: - return None - - # This will always be a list because of the check before - # pylint: disable=E1133 - for folder in self.library_folders: - if appid in folder["apps"].keys(): - return folder["path"] - return None - - def __get_local_config(self) -> dict: - if self.localconfig_path is None: - return {} - - with open(self.localconfig_path, errors="replace") as f: - data = SteamUtils.parse_vdf(f.read()) - - if data is None: - logging.warning("Could not parse localconfig.vdf") - return {} - - return data - - def save_local_config(self, new_data: dict): - if self.localconfig_path is None: - return - - if os.path.isfile(self.localconfig_path): - now = datetime.now().strftime("%Y-%m-%d_%H-%M-%S") - shutil.copy(self.localconfig_path, f"{self.localconfig_path}.bck.{now}") - - with open(self.localconfig_path, "w") as f: - SteamUtils.to_vdf(VDFDict(new_data), f) - - logging.info("Steam config saved") - - @staticmethod - @lru_cache - def get_runner_path(pfx_path: str) -> str | None: - """Get runner path from config_info file""" - config_info = os.path.join(pfx_path, "config_info") - - if not os.path.isfile(config_info): - return None - - with open(config_info) as f: - lines = f.readlines() - if len(lines) < 10: - logging.error( - f"{config_info} is not valid, cannot get Steam Proton path" - ) - return None - - proton_path = lines[1].strip().removesuffix("/share/fonts/") - - if proton_path.endswith("/files"): - proton_path = proton_path.removesuffix("/files") - elif proton_path.endswith("/dist"): - proton_path = proton_path.removesuffix("/dist") - - if not SteamUtils.is_proton(proton_path): - logging.error(f"{proton_path} is not a valid Steam Proton path") - return None - - return proton_path - - def list_apps_ids(self) -> dict: - """List all apps in Steam""" - apps = ( - self.localconfig.get("UserLocalConfigStore", {}) - .get("Software", {}) - .get("Valve", {}) - .get("Steam", {}) - ) - if "apps" in apps: - apps = apps.get("apps") - elif "Apps" in apps: - apps = apps.get("Apps") - else: - apps = {} - return apps - - def get_installed_apps_as_programs(self) -> list: - """This is a Steam for Windows only function""" - if not self.is_windows: - raise NotImplementedError( - "This function is only implemented for Windows versions of Steam" - ) - - apps_ids = self.list_apps_ids() - apps = [] - - if len(apps_ids) == 0: - return [] - - for app_id in apps_ids: - _acf = self.get_acf_data(self.steam_path, app_id) - if _acf is None: - continue - - _path = _acf["AppState"].get( - "LauncherPath", "C:\\Program Files (x86)\\Steam\\steam.exe" - ) - _executable = _path.split("\\")[-1] - _folder = ManagerUtils.get_exe_parent_dir(self.config, _path) - apps.append( - { - "executable": _executable, - "arguments": f"steam://run/{app_id}", - "name": _acf["AppState"]["name"], - "path": _path, - "folder": _folder, - "icon": "com.usebottles.bottles-program", - "id": str(uuid.uuid4()), - } - ) - - return apps - - def list_prefixes(self) -> dict[str, BottleConfig]: - apps = self.list_apps_ids() - prefixes = {} - - if len(apps) == 0: - return {} - - for appid, appdata in apps.items(): - _library_path = self.get_appid_library_path(appid) - if _library_path is None: - continue - - _path = os.path.join(_library_path, "steamapps/compatdata", appid) - - if not os.path.isdir(os.path.join(_path, "pfx")): - logging.debug(f"{appid} does not contain a prefix") - continue - - _launch_options = self.get_launch_options(appid, appdata) - _dir_name = os.path.basename(_path) - _acf = self.get_acf_data(_library_path, _dir_name) - _runner_path = self.get_runner_path(_path) - _creation_date = datetime.fromtimestamp(os.path.getctime(_path)).strftime( - "%Y-%m-%d %H:%M:%S.%f" - ) - - if not isinstance(_acf, dict): - # WORKAROUND: for corrupted acf files, this is not at our fault - continue - - if _acf is None or not _acf.get("AppState"): - logging.warning( - f"A Steam prefix was found, but there is no ACF for it: {_dir_name}, skipping…" - ) - continue - - if SteamUtils.is_proton( - os.path.join( - _library_path, - "steamapps/common", - _acf["AppState"].get("installdir", ""), - ) - ): - # skip Proton default prefix - logging.warning( - f"A Steam prefix was found, but it is a Proton one: {_dir_name}, skipping…" - ) - continue - - if _runner_path is None: - logging.warning( - f"A Steam prefix was found, but there is no Proton for it: {_dir_name}, skipping…" - ) - continue - - _conf = BottleConfig() - _conf.Name = _acf["AppState"].get("name", "Unknown") - _conf.Environment = "Steam" - _conf.CompatData = _dir_name - _conf.Path = os.path.join(_path, "pfx") - _conf.Runner = os.path.basename(_runner_path) - _conf.RunnerPath = _runner_path - _conf.WorkingDir = os.path.join(_conf.get("Path", ""), "drive_c") - _conf.Creation_Date = _creation_date - _conf.Update_Date = datetime.fromtimestamp( - int(_acf["AppState"].get("LastUpdated", 0)) - ).strftime("%Y-%m-%d %H:%M:%S.%f") - - # Launch options - _conf.Parameters.mangohud = "mangohud" in _launch_options.get("command", "") - _conf.Parameters.gamemode = "gamemode" in _launch_options.get("command", "") - _conf.Environment_Variables = _launch_options.get("env_vars", {}) - for p in _launch_options.get("env_params", {}): - _conf.Parameters[p] = _launch_options["env_params"].get(p, "") - - prefixes[_dir_name] = _conf - - return prefixes - - def update_bottles(self): - prefixes = self.list_prefixes() - - with contextlib.suppress(FileNotFoundError): - shutil.rmtree(Paths.steam) # generate new configs at start - - for _, conf in prefixes.items(): - _bottle = os.path.join(Paths.steam, conf.CompatData) - - os.makedirs(_bottle, exist_ok=True) - - conf.dump(os.path.join(_bottle, "bottle.yml")) - - def get_app_config(self, prefix: str) -> dict: - _fail_msg = f"Fail to get app config from Steam for: {prefix}" - - if len(self.localconfig) == 0: - logging.warning(_fail_msg) - return {} - - apps = ( - self.localconfig.get("UserLocalConfigStore", {}) - .get("Software", {}) - .get("Valve", {}) - .get("Steam", {}) - ) - if "apps" in apps: - apps = apps.get("apps") - elif "Apps" in apps: - apps = apps.get("Apps") - else: - apps = {} - - if len(apps) == 0 or prefix not in apps: - logging.warning(_fail_msg) - return {} - - return apps[prefix] - - def get_launch_options(self, prefix: str, app_conf: dict | None = None) -> {}: - if app_conf is None: - app_conf = self.get_app_config(prefix) - - launch_options = app_conf.get("LaunchOptions", "") - _fail_msg = f"Fail to get launch options from Steam for: {prefix}" - res = {"command": "", "args": "", "env_vars": {}, "env_params": {}} - - if len(launch_options) == 0: - logging.debug(_fail_msg) - return res - - command, args, env_vars = SteamUtils.handle_launch_options(launch_options) - res = {"command": command, "args": args, "env_vars": env_vars, "env_params": {}} - tmp_env_vars = res["env_vars"].copy() - - for e in tmp_env_vars: - if e in Samples.bottles_to_steam_relations: - k, v = Samples.bottles_to_steam_relations[e] - if v is None: - v = tmp_env_vars[e] - res["env_params"][k] = v - del res["env_vars"][e] - - return res - - # noinspection PyTypeChecker - def set_launch_options(self, prefix: str, options: dict): - original_launch_options = self.get_launch_options(prefix) - _fail_msg = f"Fail to set launch options for: {prefix}" - - if 0 in [len(self.localconfig), len(original_launch_options)]: - logging.warning(_fail_msg) - return - - command = options.get("command", "") - env_vars = options.get("env_vars", {}) - - if len(env_vars) > 0: - for k, v in env_vars.items(): - v = shlex.quote(v) if " " in v else v - original_launch_options["env_vars"][k] = v - - launch_options = "" - - for e, v in original_launch_options["env_vars"].items(): - launch_options += f"{e}={v} " - launch_options += f"{command} %command% {original_launch_options['args']}" - - try: - self.localconfig["UserLocalConfigStore"]["Software"]["Valve"]["Steam"][ - "apps" - ][prefix]["LaunchOptions"] = launch_options - except (KeyError, TypeError): - self.localconfig["UserLocalConfigStore"]["Software"]["Valve"]["Steam"][ - "Apps" - ][prefix]["LaunchOptions"] = launch_options - - self.save_local_config(self.localconfig) - - # noinspection PyTypeChecker - def del_launch_option(self, prefix: str, key_type: str, key: str): - original_launch_options = self.get_launch_options(prefix) - key_types = ["env_vars", "command"] - _fail_msg = f"Fail to delete a launch option for: {prefix}" - - if 0 in [len(self.localconfig), len(original_launch_options)]: - logging.warning(_fail_msg) - return - - if key_type not in key_types: - logging.warning(_fail_msg + f"\nKey type: {key_type} is not valid") - return - - if key_type == "env_vars": - if key in original_launch_options["env_vars"]: - del original_launch_options["env_vars"][key] - elif key_type == "command": - if key in original_launch_options["command"]: - original_launch_options["command"] = original_launch_options[ - "command" - ].replace(key, "") - - launch_options = "" - - for e, v in original_launch_options["env_vars"].items(): - launch_options += f"{e}={v} " - - launch_options += f"{original_launch_options['command']} %command% {original_launch_options['args']}" - try: - self.localconfig["UserLocalConfigStore"]["Software"]["Valve"]["Steam"][ - "apps" - ][prefix]["LaunchOptions"] = launch_options - except (KeyError, TypeError): - self.localconfig["UserLocalConfigStore"]["Software"]["Valve"]["Steam"][ - "Apps" - ][prefix]["LaunchOptions"] = launch_options - - self.save_local_config(self.localconfig) - - def update_bottle(self, config: BottleConfig) -> BottleConfig: - pfx = config.CompatData - launch_options = self.get_launch_options(pfx) - _fail_msg = f"Fail to update bottle for: {pfx}" - - args = launch_options.get("args", "") - if isinstance(args, dict) or args == "{}": - args = "" - - winecmd = WineCommand(config, "%command%", arguments=args) - command = winecmd.get_cmd("%command%", return_steam_cmd=True) - env_vars = winecmd.get_env(launch_options["env_vars"], return_steam_env=True) - - if "%command%" in command: - command, _args = command.split("%command%") - args = args + " " + _args - - options = {"command": command, "args": args, "env_vars": env_vars} - self.set_launch_options(pfx, options) - self.config = config - return config - - @staticmethod - def launch_app(prefix: str): - logging.info(f"Launching AppID {prefix} with Steam") - uri = f"steam://rungameid/{prefix}" - SignalManager.send(Signals.GShowUri, Result(data=uri)) - - def add_shortcut(self, program_name: str, program_path: str): - logging.info(f"Adding shortcut for {program_name}") - cmd = "xdg-open" - args = "bottles:run/'{0}'/'{1}'" - - if self.userdata_path is None: - logging.warning("Userdata path is not set") - return Result(False) - - confs = glob(os.path.join(self.userdata_path, "*/config/")) - shortcut = { - "AppName": program_name, - "Exe": cmd, - "StartDir": ManagerUtils.get_bottle_path(self.config), - "icon": ManagerUtils.extract_icon(self.config, program_name, program_path), - "ShortcutPath": "", - "LaunchOptions": args.format(self.config.Name, program_name), - "IsHidden": 0, - "AllowDesktopConfig": 1, - "AllowOverlay": 1, - "OpenVR": 0, - "Devkit": 0, - "DevkitGameID": "", - "DevkitOverrideAppID": "", - "LastPlayTime": 0, - "tags": {"0": "Bottles"}, - } - - for c in confs: - _shortcuts = {} - _existing = {} - - if os.path.exists(os.path.join(c, "shortcuts.vdf")): - with open(os.path.join(c, "shortcuts.vdf"), "rb") as f: - try: - _existing = vdf.binary_loads(f.read()).get("shortcuts", {}) - except: - continue - - _all = list(_existing.values()) + [shortcut] - _shortcuts = {"shortcuts": {str(i): s for i, s in enumerate(_all)}} - - with open(os.path.join(c, "shortcuts.vdf"), "wb") as f: - f.write(vdf.binary_dumps(_shortcuts)) - - logging.info(f"Added shortcut for {program_name}") - return Result(True) diff --git a/bottles/backend/wine/winecommand.py b/bottles/backend/wine/winecommand.py index ec2be392f4d..122f3cdd88d 100644 --- a/bottles/backend/wine/winecommand.py +++ b/bottles/backend/wine/winecommand.py @@ -547,39 +547,6 @@ def get_cmd( if obs_vkc_available and params.obsvkc: command = f"{obs_vkc_available} {command}" - if params.use_steam_runtime: - _rs = RuntimeManager.get_runtimes("steam") - _picked = {} - - if _rs: - if "sniper" in _rs.keys() and "sniper" in self.runner_runtime: - """ - Sniper is the default runtime used by Proton version >= 8.0 - """ - _picked = _rs["sniper"] - elif "soldier" in _rs.keys() and "soldier" in self.runner_runtime: - """ - Sniper is the default runtime used by Proton version >= 5.13 and < 8.0 - """ - _picked = _rs["soldier"] - elif "scout" in _rs.keys(): - """ - For Wine runners, we cannot make assumption about which runtime would suits - them the best, as it would depend on their build environment. - Sniper/Soldier are not backward-compatible, defaulting to Scout should maximize compatibility. - """ - _picked = _rs["scout"] - else: - logging.warning("Steam runtime was requested but not found") - - if _picked: - logging.info(f"Using Steam runtime {_picked['name']}") - command = f"{_picked['entry_point']} {command}" - else: - logging.warning( - "Steam runtime was requested and found but there are no valid combinations" - ) - if self.arguments: prefix, suffix, extracted_env = SteamUtils.handle_launch_options( self.arguments diff --git a/bottles/frontend/library_entry.py b/bottles/frontend/library_entry.py index 9679d98b746..6c9b52c2284 100644 --- a/bottles/frontend/library_entry.py +++ b/bottles/frontend/library_entry.py @@ -38,7 +38,6 @@ class LibraryEntry(Gtk.Box): # region Widgets btn_run = Gtk.Template.Child() btn_stop = Gtk.Template.Child() - btn_launch_steam = Gtk.Template.Child() btn_remove = Gtk.Template.Child() label_name = Gtk.Template.Child() label_bottle = Gtk.Template.Child() @@ -101,7 +100,6 @@ def __init__(self, library, uuid, entry, *args, **kwargs): motion_ctrl.connect("leave", self.__on_motion_leave) self.overlay.add_controller(motion_ctrl) self.btn_run.connect("clicked", self.run_executable) - self.btn_launch_steam.connect("clicked", self.run_steam) self.btn_stop.connect("clicked", self.stop_process) self.btn_remove.connect("clicked", self.__remove_entry) @@ -175,9 +173,6 @@ def run_executable(self, widget, with_terminal=False): ) self.__reset_buttons() - def run_steam(self, widget): - self.manager.steam_manager.launch_app(self.config.CompatData) - def stop_process(self, widget): self.window.show_toast(_('Stopping "{0}"…').format(self.program["name"])) winedbg = WineDbg(self.config) diff --git a/bottles/frontend/preferences.py b/bottles/frontend/preferences.py index fdcdf722cfa..c30e23af873 100644 --- a/bottles/frontend/preferences.py +++ b/bottles/frontend/preferences.py @@ -169,13 +169,6 @@ def __init__(self, window, **kwargs): self.btn_bottles_path_reset.connect("clicked", self.__reset_bottles_path) self.btn_steam_proton_doc.connect("clicked", self.__open_steam_proton_doc) - if not self.manager.steam_manager.is_steam_supported: - self.switch_steam.set_sensitive(False) - self.action_steam_proton.set_tooltip_text( - _("Steam was not found or Bottles does not have enough permissions.") - ) - self.btn_steam_proton_doc.set_visible(True) - if not self.style_manager.get_system_supports_color_schemes(): self.row_theme.set_visible(True) diff --git a/bottles/frontend/program_row.py b/bottles/frontend/program_row.py index 7a75a25f486..77928eff77c 100644 --- a/bottles/frontend/program_row.py +++ b/bottles/frontend/program_row.py @@ -42,7 +42,6 @@ class ProgramRow(Adw.ActionRow): btn_run = Gtk.Template.Child() btn_stop = Gtk.Template.Child() btn_launch_options = Gtk.Template.Child() - btn_launch_steam = Gtk.Template.Child() btn_uninstall = Gtk.Template.Child() btn_remove = Gtk.Template.Child() btn_hide = Gtk.Template.Child() @@ -71,16 +70,7 @@ def __init__( self.set_title(self.program["name"]) - if is_steam: - self.set_subtitle("Steam") - for w in [self.btn_run, self.btn_stop, self.btn_menu]: - w.set_visible(False) - w.set_sensitive(False) - self.btn_launch_steam.set_visible(True) - self.btn_launch_steam.set_sensitive(True) - self.set_activatable_widget(self.btn_launch_steam) - else: - self.executable = program.get("executable", "") + self.executable = program.get("executable", "") if program.get("removed"): self.add_css_class("removed") @@ -91,9 +81,6 @@ def __init__( self.btn_hide.set_visible(not program.get("removed")) self.btn_unhide.set_visible(program.get("removed")) - if self.manager.steam_manager.is_steam_supported: - self.btn_add_steam.set_visible(True) - library_manager = LibraryManager() for _uuid, entry in library_manager.get_library().items(): if entry.get("id") == program.get("id"): @@ -105,7 +92,6 @@ def __init__( """Signal connections""" self.btn_run.connect("clicked", self.run_executable) - self.btn_launch_steam.connect("clicked", self.run_steam) self.btn_launch_terminal.connect("clicked", self.run_executable, True) self.btn_stop.connect("clicked", self.stop_process) self.btn_launch_options.connect("clicked", self.show_launch_options_view) @@ -178,13 +164,6 @@ def _run(): RunAsync(_run, callback=self.__reset_buttons) self.__reset_buttons() - def run_steam(self, _widget): - self.manager.steam_manager.launch_app(self.config.CompatData) - self.window.show_toast( - _('Launching "{0}" with Steam…').format(self.program["name"]) - ) - self.pop_actions.popdown() # workaround #1640 - def stop_process(self, widget): self.window.show_toast(_('Stopping "{0}"…').format(self.program["name"])) winedbg = WineDbg(self.config) From 68e20d255de7edc46419042cc40bea4cc8b73364 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Wed, 22 Jan 2025 22:30:41 -0500 Subject: [PATCH 104/146] backend: Remove ComponentManager --- bottles/backend/managers/component.py | 492 ------------------------- bottles/backend/managers/dependency.py | 127 +------ bottles/backend/managers/installer.py | 36 -- bottles/backend/managers/manager.py | 26 -- bottles/backend/managers/meson.build | 1 - 5 files changed, 1 insertion(+), 681 deletions(-) delete mode 100644 bottles/backend/managers/component.py diff --git a/bottles/backend/managers/component.py b/bottles/backend/managers/component.py deleted file mode 100644 index 7eb46456789..00000000000 --- a/bottles/backend/managers/component.py +++ /dev/null @@ -1,492 +0,0 @@ -# component.py -# -# Copyright 2022 brombinmirko -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, in version 3 of the License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# - -import contextlib -import os -import shutil -import tarfile -from functools import lru_cache - -import pycurl - -from bottles.backend.downloader import Downloader -from bottles.backend.globals import Paths -from bottles.backend.logger import Logger -from bottles.backend.models.result import Result -from bottles.backend.state import ( - Locks, - Task, - TaskStreamUpdateHandler, - Status, - TaskManager, - LockManager, -) -from bottles.backend.utils.file import FileUtils -from bottles.backend.utils.generic import is_glibc_min_available -from bottles.backend.utils.manager import ManagerUtils -from bottles.backend.repos.component import ComponentRepo - -logging = Logger() - - -# noinspection PyTypeChecker -class ComponentManager: - def __init__(self, manager): - self.__manager = manager - - url = "https://proxy.usebottles.com/repo/components/" - self.__repo = ComponentRepo(url, "") - - @lru_cache - def get_component(self, name: str, plain: bool = False) -> dict: - return self.__repo.get(name, plain) - - def fetch_catalog(self) -> dict: - """ - Fetch all components from the Bottles repository, mark the installed - ones and return a dict with the catalog. - """ - catalog = { - "runtimes": {}, - "wine": {}, - "proton": {}, - "dxvk": {}, - "vkd3d": {}, - "nvapi": {}, - "latencyflex": {}, - "winebridge": {}, - } - components_available = { - "runtimes": self.__manager.runtimes_available, - "wine": self.__manager.runners_available, - "proton": self.__manager.runners_available, - "dxvk": self.__manager.dxvk_available, - "vkd3d": self.__manager.vkd3d_available, - "nvapi": self.__manager.nvapi_available, - "latencyflex": self.__manager.latencyflex_available, - "winebridge": self.__manager.winebridge_available, - } - - index = self.__repo.catalog - - for component in index.items(): - """ - For each component, append it to the corresponding - catalog and mark it as installed if it is. - """ - - if component[1]["Category"] == "runners": - if "soda" in component[0].lower() or "caffe" in component[0].lower(): - if not is_glibc_min_available(): - logging.warning( - f"{component[0]} was found but it requires " - "glibc >= 2.32 and your system is running an older " - "version. Use the Flatpak instead if you can't " - "upgrade your system. This runner will be ignored, " - "please keep in mind that Bottles and all our " - "installers are only tested with Soda and Caffe runners." - ) - continue - - sub_category = component[1]["Sub-category"] - catalog[sub_category][component[0]] = component[1] - if component[0] in components_available[sub_category]: - catalog[sub_category][component[0]]["Installed"] = True - else: - catalog[sub_category][component[0]].pop("Installed", None) - - continue - - category = component[1]["Category"] - if category not in catalog: - continue - - catalog[category][component[0]] = component[1] - if component[0] in components_available[category]: - catalog[category][component[0]]["Installed"] = True - else: - catalog[category][component[0]].pop("Installed", None) - - return catalog - - def download( - self, - download_url: str, - file: str, - rename: str = "", - checksum: str = "", - func: TaskStreamUpdateHandler | None = None, - ) -> bool: - """Download a component from the Bottles repository.""" - - # Check for missing Bottles paths before download - self.__manager.check_app_dirs() - - # Register this file download task to TaskManager - task = Task(title=file) - task_id = TaskManager.add(task) - update_func = task.stream_update if not func else func - - if download_url.startswith("temp/"): - """ - The caller is explicitly requesting a component from - the /temp directory. Nothing should be downloaded. - """ - return True - - existing_file = rename if rename else file - temp_dest = os.path.join(Paths.temp, file) - just_downloaded = False - - if os.path.isfile(os.path.join(Paths.temp, existing_file)): - """ - Check if the file already exists in the /temp directory. - If so, then skip the download process and set the update_func - to completed. - """ - logging.warning(f"File [{existing_file}] already exists in temp, skipping.") - else: - """ - As some urls can be redirect, we need to take care of this - and make sure to use the final url. This check should be - skipped for large files (e.g. runners). - """ - c = pycurl.Curl() - try: - c.setopt(c.URL, download_url) # type: ignore - c.setopt(c.FOLLOWLOCATION, True) # type: ignore - c.setopt(c.HTTPHEADER, ["User-Agent: curl/7.79.1"]) # type: ignore - c.setopt(c.NOBODY, True) # type: ignore - c.perform() - - req_code = c.getinfo(c.RESPONSE_CODE) # type: ignore - download_url = c.getinfo(c.EFFECTIVE_URL) # type: ignore - except pycurl.error: - logging.exception(f"Failed to download [{download_url}]") - TaskManager.remove(task_id) - return False - finally: - c.close() - - if req_code == 200: - """ - If the status code is 200, the resource should be available - and the download should be started. Any exceptions return - False and the download is removed from the download manager. - """ - res = Downloader( - url=download_url, file=temp_dest, update_func=update_func - ).download() - - if not res.ok: - TaskManager.remove(task_id) - return False - - if not os.path.isfile(temp_dest): - """Fail if the file is not available in the /temp directory.""" - TaskManager.remove(task_id) - return False - - just_downloaded = True - else: - logging.warning( - f"Failed to download [{download_url}] with code: {req_code} != 200" - ) - TaskManager.remove(task_id) - return False - - file_path = os.path.join(Paths.temp, existing_file) - if rename and just_downloaded: - """Renaming the downloaded file if requested.""" - logging.info(f"Renaming [{file}] to [{rename}].") - file_path = os.path.join(Paths.temp, rename) - os.rename(temp_dest, file_path) - - if checksum and not os.environ.get("BOTTLES_SKIP_CHECKSUM"): - """ - Compare the checksum of the downloaded file with the one - provided by the caller. If they don't match, remove the - file from the /temp directory, remove the entry from the - task manager and return False. - """ - checksum = checksum.lower() - local_checksum = FileUtils().get_checksum(file_path) - - if local_checksum and local_checksum != checksum: - logging.error(f"Downloaded file [{file}] looks corrupted.") - logging.error( - f"Source cksum: [{checksum}] downloaded: [{local_checksum}]" - ) - logging.error(f"Removing corrupted file [{file}].") - os.remove(file_path) - TaskManager.remove(task_id) - return False - - TaskManager.remove(task_id) - return True - - @staticmethod - def extract(name: str, component: str, archive: str) -> bool: - """Extract a component from an archive.""" - - if component in ["runner", "runner:proton"]: - path = Paths.runners - elif component == "dxvk": - path = Paths.dxvk - elif component == "vkd3d": - path = Paths.vkd3d - elif component == "nvapi": - path = Paths.nvapi - elif component == "latencyflex": - path = Paths.latencyflex - elif component == "runtime": - path = Paths.runtimes - elif component == "winebridge": - path = Paths.winebridge - else: - logging.error(f"Unknown component [{component}].") - return False - - try: - """ - Try to extract the archive in the /temp directory. - If the extraction fails, remove the archive from the /temp - directory and return False. The common cause of a failed - extraction is that the archive is corrupted. - """ - tar = tarfile.open(f"{Paths.temp}/{archive}") - root_dir = tar.getnames()[0] - tar.extractall(path) - tar.close() - except (tarfile.TarError, OSError, EOFError): - with contextlib.suppress(FileNotFoundError): - os.remove(os.path.join(Paths.temp, archive)) - with contextlib.suppress(FileNotFoundError): - shutil.rmtree(os.path.join(path, archive[:-7])) - - logging.error("Extraction failed! Archive ends earlier than expected.") - return False - - if root_dir.endswith("x86_64"): - try: - """ - If the folder ends with x86_64, remove this from its name. - Return False if an folder with the same name already exists. - """ - root_dir = os.path.join(path, root_dir) - shutil.move(src=root_dir, dst=root_dir[:-7]) - except (FileExistsError, shutil.Error): - logging.error("Extraction failed! Component already exists.") - return False - return True - - @LockManager.lock(Locks.ComponentsInstall) # avoid high resource usage - def install( - self, - component_type: str, - component_name: str, - func: TaskStreamUpdateHandler | None = None, - ): - """ - This function is used to install a component. It automatically - gets the manifest from the given component and then calls the - download and extract functions. - """ - manifest = self.get_component(component_name) - - if not manifest: - return Result(False) - - logging.info(f"Installing component: [{component_name}].") - file = manifest["File"][0] - - res = self.download( - download_url=file["url"], - file=file["file_name"], - rename=file["rename"], - checksum=file["file_checksum"], - func=func, - ) - - if not res: - """ - If the download fails, execute the given func passing - failed=True as a parameter. - """ - if func: - func(status=Status.FAILED) - return Result(False) - - archive = manifest["File"][0]["file_name"] - - if manifest["File"][0]["rename"]: - """ - If the component has a rename, rename the downloaded file - to the required name. - """ - archive = manifest["File"][0]["rename"] - - self.extract(component_name, component_type, archive) - - """ - Execute Post Install if the component has it defined - in the manifest. - """ - if "Post" in manifest: - print(f"Executing post install for [{component_name}].") - - for post in manifest.get("Post", []): - if post["action"] == "rename": - self.__post_rename(component_type, post) - - """ - Ask the manager to re-organize its components. - Note: I know that this is not the most efficient way to do this, - please give feedback if you know a better way to avoid this. - """ - if component_type in ["runtime", "winebridge"]: - with contextlib.suppress(FileNotFoundError): - os.remove(os.path.join(Paths.temp, archive)) - - if component_type in ["runner", "runner:proton"]: - self.__manager.check_runners() - - elif component_type == "dxvk": - self.__manager.check_dxvk() - - elif component_type == "vkd3d": - self.__manager.check_vkd3d() - - elif component_type == "nvapi": - self.__manager.check_nvapi() - - elif component_type == "runtime": - self.__manager.check_runtimes() - - elif component_type == "winebridge": - self.__manager.check_winebridge() - - self.__manager.organize_components() - logging.info(f"Component installed: {component_type} {component_name}", jn=True) - - return Result(True) - - @staticmethod - def __post_rename(component_type: str, post: dict): - source = post.get("source") - dest = post.get("dest") - - if component_type in ["runner", "runner:proton"]: - path = Paths.runners - elif component_type == "dxvk": - path = Paths.dxvk - elif component_type == "vkd3d": - path = Paths.vkd3d - elif component_type == "nvapi": - path = Paths.nvapi - else: - logging.error(f"Unknown component type: {component_type}") - return - - if ( - source is not None - and dest is not None - and not os.path.isdir(os.path.join(path, dest)) - ): - shutil.move(src=os.path.join(path, source), dst=os.path.join(path, dest)) - - def is_in_use(self, component_type: str, component_name: str): - bottles = self.__manager.local_bottles - - if component_type in ["runner", "runner:proton"]: - return component_name in [b["Runner"] for _, b in bottles.items()] - if component_type == "dxvk": - return component_name in [b["DXVK"] for _, b in bottles.items()] - if component_type == "vkd3d": - return component_name in [b["VKD3D"] for _, b in bottles.items()] - if component_type == "nvapi": - return component_name in [b["NVAPI"] for _, b in bottles.items()] - if component_type == "latencyflex": - return component_name in [b["LatencyFleX"] for _, b in bottles.items()] - if component_type in ["runtime", "winebridge"]: - return True - return False - - def uninstall(self, component_type: str, component_name: str): - if self.is_in_use(component_type, component_name): - return Result( - False, - data={ - "message": f"Component in use and cannot be removed: {component_name}" - }, - ) - - if component_type in ["runner", "runner:proton"]: - path = ManagerUtils.get_runner_path(component_name) - - elif component_type == "dxvk": - path = ManagerUtils.get_dxvk_path(component_name) - - elif component_type == "vkd3d": - path = ManagerUtils.get_vkd3d_path(component_name) - - elif component_type == "nvapi": - path = ManagerUtils.get_nvapi_path(component_name) - - elif component_type == "latencyflex": - path = ManagerUtils.get_latencyflex_path(component_name) - - else: - logging.error(f"Unknown component type: {component_type}") - return Result(False, data={"message": "Unknown component type."}) - - if not os.path.isdir(path): - return Result(False, data={"message": "Component not installed."}) - - try: - shutil.rmtree(path) - except Exception as e: - logging.error(f"Failed to uninstall component: {component_name}, {e}") - return Result(False, data={"message": "Failed to uninstall component."}) - - """ - Ask the manager to re-organize its components. - Note: I know that this is not the most efficient way to do this, - please give feedback if you know a better way to avoid this. - """ - if component_type in ["runner", "runner:proton"]: - self.__manager.check_runners() - - elif component_type == "dxvk": - self.__manager.check_dxvk() - - elif component_type == "vkd3d": - self.__manager.check_vkd3d() - - elif component_type == "nvapi": - self.__manager.check_nvapi() - - elif component_type == "runtime": - self.__manager.check_runtimes() - - elif component_type == "winebridge": - self.__manager.check_winebridge() - - self.__manager.organize_components() - logging.info(f"Component uninstalled: {component_type} {component_name}") - - return Result(True) diff --git a/bottles/backend/managers/dependency.py b/bottles/backend/managers/dependency.py index fd3eb3359e4..73b9b19e9d1 100644 --- a/bottles/backend/managers/dependency.py +++ b/bottles/backend/managers/dependency.py @@ -17,7 +17,6 @@ import os import shutil -import traceback from functools import lru_cache from glob import glob @@ -30,7 +29,6 @@ from bottles.backend.models.enum import Arch from bottles.backend.models.result import Result from bottles.backend.state import TaskManager, Task -from bottles.backend.utils.generic import validate_url from bottles.backend.utils.manager import ManagerUtils from bottles.backend.wine.executor import WineExecutor from bottles.backend.wine.reg import Reg, RegItem @@ -177,14 +175,6 @@ def __perform_steps(self, config: BottleConfig, step: dict) -> Result: if step["action"] == "delete_dlls": self.__step_delete_dlls(config, step) - if step["action"] == "download_archive": - if not self.__step_download_archive(step): - return Result(status=False) - - if step["action"] in ["install_exe", "install_msi"]: - if not self.__step_install_exe_msi(config=config, step=step): - return Result(status=False) - if step["action"] == "uninstall": self.__step_uninstall(config=config, file_name=step["file_name"]) @@ -198,11 +188,6 @@ def __perform_steps(self, config: BottleConfig, step: dict) -> Result: if not self.__step_get_from_cab(config=config, step=step): return Result(status=False) - if step["action"] == "archive_extract": - uninstaller = False - if not self.__step_archive_extract(step): - return Result(status=False) - if step["action"] in ["install_cab_fonts", "install_fonts"]: uninstaller = False if not self.__step_install_fonts(config=config, step=step): @@ -263,56 +248,6 @@ def __get_real_dest(config: BottleConfig, dest: str) -> str | bool: return dest - def __step_download_archive(self, step: dict): - """ - This function download an archive from the given step. - Can be used for any file type (cab, zip, ...). Please don't - use this method for exe/msi files as the install_exe already - download the exe/msi file before installation. - """ - download = self.__manager.component_manager.download( - download_url=step.get("url"), - file=step.get("file_name"), - rename=step.get("rename"), - checksum=step.get("file_checksum"), - ) - - return download - - def __step_install_exe_msi(self, config: BottleConfig, step: dict) -> bool: - """ - Download and install the .exe or .msi file - declared in the step, in a bottle. - """ - winedbg = WineDbg(config) - download = self.__manager.component_manager.download( - download_url=step.get("url"), - file=step.get("file_name"), - rename=step.get("rename"), - checksum=step.get("file_checksum"), - ) - file = step.get("file_name") - if step.get("rename"): - file = step.get("rename") - - if download: - if step.get("url").startswith("temp/"): - _file = step.get("url").replace("temp/", f"{Paths.temp}/") - file = f"{_file}/{file}" - else: - file = f"{Paths.temp}/{file}" - executor = WineExecutor( - config, - exec_path=file, - args=step.get("arguments"), - environment=step.get("environment"), - ) - executor.run() - winedbg.wait_for_process(file) - return True - - return False - @staticmethod def __step_uninstall(config: BottleConfig, file_name: str) -> bool: """ @@ -334,28 +269,7 @@ def __step_cab_extract(self, step: dict): logging.error("Destination path not supported!") return False - if validate_url(step["url"]): - download = self.__manager.component_manager.download( - download_url=step.get("url"), - file=step.get("file_name"), - rename=step.get("rename"), - checksum=step.get("file_checksum"), - ) - - if download: - if step.get("rename"): - file = step.get("rename") - else: - file = step.get("file_name") - - if not CabExtract().run( - path=os.path.join(Paths.temp, file), name=file, destination=dest - ): - return False - else: - return False - - elif step["url"].startswith("temp/"): + if step["url"].startswith("temp/"): path = step["url"] path = path.replace("temp/", f"{Paths.temp}/") @@ -408,45 +322,6 @@ def __step_get_from_cab(self, config: BottleConfig, step: dict): return False return True - def __step_archive_extract(self, step: dict): - """Download and extract an archive to the temp folder.""" - download = self.__manager.component_manager.download( - download_url=step.get("url"), - file=step.get("file_name"), - rename=step.get("rename"), - checksum=step.get("file_checksum"), - ) - - if not download: - return False - - if step.get("rename"): - file = step.get("rename") - else: - file = step.get("file_name") - - archive_path = os.path.join(Paths.temp, os.path.splitext(file)[0]) - - if os.path.exists(archive_path): - shutil.rmtree(archive_path) - - os.makedirs(archive_path) - try: - patoolib.extract_archive( - os.path.join(Paths.temp, file), outdir=archive_path - ) - if archive_path.endswith(".tar") and os.path.isfile( - os.path.join(archive_path, os.path.basename(archive_path)) - ): - tar_path = os.path.join(archive_path, os.path.basename(archive_path)) - patoolib.extract_archive(tar_path, outdir=archive_path) - except Exception as e: - logging.error("Something wrong happened during extraction.") - logging.error(f"{e}") - logging.error(f"{traceback.format_exc()}") - return False - return True - @staticmethod def __step_install_fonts(config: BottleConfig, step: dict): """Move fonts to the drive_c/windows/Fonts path.""" diff --git a/bottles/backend/managers/installer.py b/bottles/backend/managers/installer.py index b8aad7bc3b4..218d98744b7 100644 --- a/bottles/backend/managers/installer.py +++ b/bottles/backend/managers/installer.py @@ -39,7 +39,6 @@ class InstallerManager: def __init__(self, manager): self.__manager = manager - self.__component_manager = manager.component_manager self.__local_resources = {} url = "https://proxy.usebottles.com/repo/programs/" @@ -171,41 +170,6 @@ def __perform_steps(self, config: BottleConfig, steps: list): if st.get("action") == "update_config": self.__step_update_config(config, st) - # Step type: install_exe, install_msi - if st["action"] in ["install_exe", "install_msi"]: - if st["url"] != "local": - download = self.__component_manager.download( - st.get("url"), - st.get("file_name"), - st.get("rename"), - checksum=st.get("file_checksum"), - ) - else: - download = True - - if download: - if st["url"] != "local": - if st.get("rename"): - file = st.get("rename") - else: - file = st.get("file_name") - file_path = f"{Paths.temp}/{file}" - else: - file_path = self.__local_resources[st.get("file_name")] - - executor = WineExecutor( - config, - exec_path=file_path, - args=st.get("arguments"), - environment=st.get("environment"), - monitoring=st.get("monitoring", []), - ) - executor.run() - else: - logging.error( - f"Failed to download {st.get('file_name')}, or checksum failed." - ) - return False return True @staticmethod diff --git a/bottles/backend/managers/manager.py b/bottles/backend/managers/manager.py index f6ab1388906..18e3a7cdaf6 100644 --- a/bottles/backend/managers/manager.py +++ b/bottles/backend/managers/manager.py @@ -36,7 +36,6 @@ from bottles.backend.dlls.vkd3d import VKD3DComponent from bottles.backend.globals import Paths from bottles.backend.logger import Logger -from bottles.backend.managers.component import ComponentManager from bottles.backend.managers.data import DataManager, UserDataKeys from bottles.backend.managers.dependency import DependencyManager from bottles.backend.managers.epicgamesstore import EpicGamesStoreManager @@ -124,7 +123,6 @@ def __init__( ) # sub-managers - self.component_manager = ComponentManager(self) self.installer_manager = InstallerManager(self) self.dependency_manager = DependencyManager(self) self.import_manager = ImportManager(self) @@ -173,9 +171,6 @@ def checks(self, install_latest=False, first_run=False) -> Result: self.check_runners(install_latest) or rv.set_status(False) rv.data["check_runners"] = time.time() - if first_run: - self.organize_components() - self.organize_dependencies() self.organize_installers() @@ -197,26 +192,6 @@ def check_app_dirs(self): """ map(lambda path: os.makedirs(path, exist_ok=True), Paths.get_components_paths()) - @RunAsync.run_async - def organize_components(self): - """Get components catalog and organizes into supported_ lists.""" - EventManager.wait(Events.ComponentsFetching) - catalog = self.component_manager.fetch_catalog() - if len(catalog) == 0: - EventManager.done(Events.ComponentsOrganizing) - logging.info("No components found.") - return - - self.supported_wine_runners = catalog["wine"] - self.supported_proton_runners = catalog["proton"] - self.supported_runtimes = catalog["runtimes"] - self.supported_winebridge = catalog["winebridge"] - self.supported_dxvk = catalog["dxvk"] - self.supported_vkd3d = catalog["vkd3d"] - self.supported_nvapi = catalog["nvapi"] - self.supported_latencyflex = catalog["latencyflex"] - EventManager.done(Events.ComponentsOrganizing) - @RunAsync.run_async def organize_dependencies(self): """Organizes dependencies into supported_dependencies.""" @@ -1014,7 +989,6 @@ def components_check(): self.check_vkd3d() self.check_nvapi() self.check_latencyflex() - self.organize_components() check_attempts += 1 return components_check() diff --git a/bottles/backend/managers/meson.build b/bottles/backend/managers/meson.build index ee4d29ff547..afcf2f24743 100644 --- a/bottles/backend/managers/meson.build +++ b/bottles/backend/managers/meson.build @@ -4,7 +4,6 @@ managersdir = join_paths(pkgdatadir, 'bottles/backend/managers') bottles_sources = [ '__init__.py', 'backup.py', - 'component.py', 'dependency.py', 'installer.py', 'library.py', From 8abc8b4fd9b608d3a05b7471a2e01fc0d4f11999 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Wed, 22 Jan 2025 22:37:29 -0500 Subject: [PATCH 105/146] frontend: Remove InstallerManager --- bottles/frontend/bottle_details_view.py | 6 - bottles/frontend/bottles.gresource.xml | 3 - bottles/frontend/details-installers-view.blp | 71 ------ bottles/frontend/details_installers_view.py | 130 ----------- bottles/frontend/installer-dialog.blp | 144 ------------ bottles/frontend/installer-row.blp | 76 ------- bottles/frontend/installer_dialog.py | 217 ------------------- bottles/frontend/installer_row.py | 106 --------- bottles/frontend/meson.build | 6 - 9 files changed, 759 deletions(-) delete mode 100644 bottles/frontend/details-installers-view.blp delete mode 100644 bottles/frontend/details_installers_view.py delete mode 100644 bottles/frontend/installer-dialog.blp delete mode 100644 bottles/frontend/installer-row.blp delete mode 100644 bottles/frontend/installer_dialog.py delete mode 100644 bottles/frontend/installer_row.py diff --git a/bottles/frontend/bottle_details_view.py b/bottles/frontend/bottle_details_view.py index ea2e573440a..321b49b2d0a 100644 --- a/bottles/frontend/bottle_details_view.py +++ b/bottles/frontend/bottle_details_view.py @@ -26,7 +26,6 @@ from bottles.backend.utils.threading import RunAsync from bottles.frontend.gtk import GtkUtils from bottles.frontend.bottle_details_page import BottleDetailsPage -from bottles.frontend.details_installers_view import DetailsInstallersView from bottles.frontend.details_dependencies_view import DetailsDependenciesView from bottles.frontend.details_preferences_page import DetailsPreferencesPage from bottles.frontend.details_task_manager_view import DetailsTaskManagerView @@ -73,7 +72,6 @@ def __init__(self, window, config: BottleConfig | None = None, **kwargs): self.queue = QueueManager(add_fn=self.lock_back, end_fn=self.unlock_back) self.view_bottle = BottleDetailsPage(self, config) - self.view_installers = DetailsInstallersView(self, config) self.view_dependencies = DetailsDependenciesView(self, config) self.view_preferences = DetailsPreferencesPage(self, config) self.view_taskmanager = DetailsTaskManagerView(self, config) @@ -117,8 +115,6 @@ def __on_page_change(self, *_args): if page == "dependencies": self.set_actions(self.view_dependencies.actions) self.view_dependencies.update(config=self.config) - elif page == "installers": - self.set_actions(self.view_installers.actions) elif page == "taskmanager": self.set_actions(self.view_taskmanager.actions) else: @@ -162,7 +158,6 @@ def ui_update(): self.stack_bottle.add_named(self.view_preferences, "preferences") self.stack_bottle.add_named(self.view_dependencies, "dependencies") - self.stack_bottle.add_named(self.view_installers, "installers") self.stack_bottle.add_named(self.view_taskmanager, "taskmanager") if self.view_bottle.actions.get_parent() is None: @@ -193,7 +188,6 @@ def set_config(self, config: BottleConfig, rebuild_pages=True): self.view_bottle.set_config(config=config) self.view_preferences.set_config(config=config) self.view_taskmanager.set_config(config=config) - self.view_installers.update(config=config) if rebuild_pages: self.build_pages() diff --git a/bottles/frontend/bottles.gresource.xml b/bottles/frontend/bottles.gresource.xml index 9f08d7e169e..91951d987cd 100644 --- a/bottles/frontend/bottles.gresource.xml +++ b/bottles/frontend/bottles.gresource.xml @@ -14,7 +14,6 @@ dependency-entry-row.ui program-row.ui importer-row.ui - installer-row.ui dll-override-entry.ui env-var-entry.ui component-entry-row.ui @@ -24,7 +23,6 @@ bottle-details-view.ui bottle-details-page.ui details-dependencies-view.ui - details-installers-view.ui details-preferences-page.ui details-task-manager-view.ui preferences.ui @@ -44,7 +42,6 @@ drives-dialog.ui journal-dialog.ui sandbox-dialog.ui - installer-dialog.ui bottle-picker-dialog.ui proton-alert-dialog.ui dependencies-check-dialog.ui diff --git a/bottles/frontend/details-installers-view.blp b/bottles/frontend/details-installers-view.blp deleted file mode 100644 index c4dec9dcb5b..00000000000 --- a/bottles/frontend/details-installers-view.blp +++ /dev/null @@ -1,71 +0,0 @@ -using Gtk 4.0; -using Adw 1; - -template $DetailsInstallersView: Adw.Bin { - Box { - orientation: vertical; - - SearchBar search_bar { - SearchEntry entry_search { - placeholder-text: _("Search for Programs…"); - } - } - - Adw.PreferencesPage pref_page { - Adw.PreferencesGroup { - description: _("Install programs curated by our community.\n\nFiles on this page are provided by third parties under a proprietary license. By installing them, you agree with their respective licensing terms."); - - ListBox list_installers { - selection-mode: none; - - styles [ - "boxed-list", - ] - } - } - } - - Adw.StatusPage status_page { - icon-name: "system-software-install-symbolic"; - title: _("No Installers Found"); - vexpand: true; - hexpand: true; - description: _("The repository is unreachable or no installer is compatible with this bottle."); - } - } -} - -Popover pop_context { - styles [ - "menu", - ] - - Box { - orientation: vertical; - margin-top: 6; - margin-bottom: 6; - margin-start: 6; - margin-end: 6; - - $GtkModelButton btn_help { - tooltip-text: _("Read Documentation"); - text: _("Documentation"); - } - } -} - -Box actions { - spacing: 6; - - ToggleButton btn_toggle_search { - active: bind search_bar.search-mode-enabled no-sync-create bidirectional; - tooltip-text: _("Search"); - icon-name: "system-search-symbolic"; - } - - MenuButton { - popover: pop_context; - icon-name: "view-more-symbolic"; - tooltip-text: _("Secondary Menu"); - } -} diff --git a/bottles/frontend/details_installers_view.py b/bottles/frontend/details_installers_view.py deleted file mode 100644 index e6059475fd7..00000000000 --- a/bottles/frontend/details_installers_view.py +++ /dev/null @@ -1,130 +0,0 @@ -# details_installers_view.py -# -# Copyright 2025 The Bottle Contributors -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, in version 3 of the License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# - -import time -from gi.repository import Gtk, GLib, Adw - -from bottles.backend.models.config import BottleConfig -from bottles.backend.models.result import Result - -from bottles.backend.utils.threading import RunAsync -from bottles.frontend.common import open_doc_url -from bottles.frontend.installer_row import InstallerRow - - -@Gtk.Template(resource_path="/com/usebottles/bottles/details-installers-view.ui") -class DetailsInstallersView(Adw.Bin): - __gtype_name__ = "DetailsInstallersView" - __registry = [] - - # region Widgets - list_installers = Gtk.Template.Child() - btn_help = Gtk.Template.Child() - btn_toggle_search = Gtk.Template.Child() - entry_search = Gtk.Template.Child() - search_bar = Gtk.Template.Child() - actions = Gtk.Template.Child() - pref_page = Gtk.Template.Child() - status_page = Gtk.Template.Child() - ev_controller = Gtk.EventControllerKey.new() - - # endregion - - def __init__(self, details, config, **kwargs): - super().__init__(**kwargs) - - # common variables and references - self.window = details.window - self.manager = details.window.manager - self.config = config - - self.ev_controller.connect("key-released", self.__search_installers) - self.entry_search.add_controller(self.ev_controller) - - self.search_bar.set_key_capture_widget(self.window) - self.btn_help.connect("clicked", open_doc_url, "bottles/installers") - self.entry_search.connect("changed", self.__search_installers) - - def __search_installers(self, *_args): - """ - This function search in the list of installers the - text written in the search entry. - """ - terms = self.entry_search.get_text() - self.list_installers.set_filter_func(self.__filter_installers, terms) - - @staticmethod - def __filter_installers(row, terms=None): - text = row.get_title().lower() + row.get_subtitle().lower() - if terms.lower() in text: - return True - return False - - def empty_list(self): - for r in self.__registry: - if r.get_parent() is not None: - r.get_parent().remove(r) - self.__registry = [] - - def update(self, widget=False, config=None): - """ - This function update the installers list with the - supported by the manager. - """ - if config is None: - config = BottleConfig() - self.config = config - installers = self.manager.supported_installers.items() - - self.list_installers.set_sensitive(False) - - def new_installer(_installer): - entry = InstallerRow( - window=self.window, config=self.config, installer=_installer - ) - self.list_installers.append(entry) - self.__registry.append(entry) - - def callback(result, error=False): - self.status_page.set_visible(not result.status) - self.pref_page.set_visible(result.status) - self.list_installers.set_visible(result.status) - self.list_installers.set_sensitive(result.status) - - def process_installers(): - time.sleep(0.5) # workaround for freezing bug on bottle load - GLib.idle_add(self.empty_list) - - if len(installers) == 0: - return Result(False) - - i = 0 - - for installer in installers: - if len(installer) != 2: - continue - if installer[1].get("Arch", "win64") != self.config.Arch: - continue - GLib.idle_add(new_installer, installer) - i += 1 - - if i == 0: - return Result(False) # there are no arch-compatible installers - - return Result(True) - - RunAsync(process_installers, callback) diff --git a/bottles/frontend/installer-dialog.blp b/bottles/frontend/installer-dialog.blp deleted file mode 100644 index a1f843d7d92..00000000000 --- a/bottles/frontend/installer-dialog.blp +++ /dev/null @@ -1,144 +0,0 @@ -using Gtk 4.0; -using Adw 1; - -template $InstallerDialog: Adw.Window { - modal: true; - deletable: true; - default-width: 500; - default-height: 600; - - Box { - orientation: vertical; - - Adw.HeaderBar { - title-widget: Adw.WindowTitle window_title {}; - - styles [ - "flat", - ] - } - - Stack stack { - vexpand: true; - - StackPage page_init { - name: "page_init"; - - child: Box { - orientation: vertical; - spacing: 10; - valign: center; - halign: fill; - - Image img_icon { - halign: center; - } - - Adw.StatusPage status_init { - description: _("Do you want to proceed with the installation?"); - hexpand: true; - vexpand: true; - - Button btn_install { - label: _("Start Installation"); - halign: center; - - styles [ - "pill", - "suggested-action", - ] - } - } - }; - } - - StackPage page_resources { - name: "page_resources"; - - child: Adw.PreferencesPage { - Adw.PreferencesGroup group_resources { - description: _("This installer requires some local resources which cannot be provided otherwise."); - } - - Button btn_proceed { - label: _("Proceed"); - sensitive: false; - visible: false; - halign: center; - valign: center; - - styles [ - "pill", - "suggested-action", - ] - } - }; - } - - StackPage page_install { - name: "page_install"; - - child: Box { - margin-top: 10; - margin-start: 10; - margin-bottom: 10; - margin-end: 10; - orientation: vertical; - valign: center; - spacing: 5; - - Image img_icon_install { - halign: center; - margin-bottom: 2; - } - - Adw.StatusPage install_status_page { - title: "name"; - description: _("This could take a while."); - - ProgressBar progressbar { - width-request: 300; - halign: center; - margin-top: 10; - margin-bottom: 12; - show-text: true; - - styles [ - "installer", - ] - } - } - }; - } - - StackPage page_installed { - name: "page_installed"; - - child: Adw.StatusPage status_installed { - icon-name: "selection-mode-symbolic"; - title: _("Completed!"); - - Button btn_close { - label: _("Show Programs"); - halign: center; - - styles [ - "pill", - "suggested-action", - ] - } - }; - } - - StackPage page_error { - name: "page_error"; - - child: Adw.StatusPage status_error { - icon-name: "dialog-warning-symbolic"; - title: _("Installation Failed!"); - description: _("Something went wrong."); - }; - } - } - } -} diff --git a/bottles/frontend/installer-row.blp b/bottles/frontend/installer-row.blp deleted file mode 100644 index 50f530d4312..00000000000 --- a/bottles/frontend/installer-row.blp +++ /dev/null @@ -1,76 +0,0 @@ -using Gtk 4.0; -using Adw 1; - -Popover pop_actions { - styles [ - "menu", - ] - - Box { - orientation: vertical; - margin-top: 6; - margin-bottom: 6; - margin-start: 6; - margin-end: 6; - - $GtkModelButton btn_manifest { - text: _("Show Manifest…"); - } - - $GtkModelButton btn_review { - text: _("Read Review…"); - } - - Separator {} - - $GtkModelButton btn_report { - text: _("Report a Bug…"); - } - } -} - -template $InstallerRow: Adw.ActionRow { - activatable-widget: btn_install; - title: _("Installer name"); - subtitle: _("Installer description"); - - Box { - spacing: 6; - - Label label_grade { - valign: center; - label: _("Unknown"); - - styles [ - "tag", - "caption", - ] - } - - Button btn_install { - tooltip-text: _("Install this Program"); - valign: center; - icon-name: "document-save-symbolic"; - - styles [ - "flat", - ] - } - - Separator { - margin-top: 12; - margin-bottom: 12; - } - - MenuButton { - valign: center; - popover: pop_actions; - icon-name: "view-more-symbolic"; - tooltip-text: _("Program Menu"); - - styles [ - "flat", - ] - } - } -} diff --git a/bottles/frontend/installer_dialog.py b/bottles/frontend/installer_dialog.py deleted file mode 100644 index 775c1648ff8..00000000000 --- a/bottles/frontend/installer_dialog.py +++ /dev/null @@ -1,217 +0,0 @@ -# installer_dialog.py -# -# Copyright 2025 The Bottles Contributors -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, in version 3 of the License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# - -import urllib.request - -from gettext import gettext as _ -from gi.repository import Gtk, GLib, Gio, GdkPixbuf, Adw - -from bottles.backend.utils.threading import RunAsync -from bottles.frontend.gtk import GtkUtils - - -@Gtk.Template(resource_path="/com/usebottles/bottles/local-resource-row.ui") -class LocalResourceRow(Adw.ActionRow): - __gtype_name__ = "LocalResourceRow" - - # region Widgets - btn_path = Gtk.Template.Child() - - # endregion - - def __init__(self, parent, resource, **kwargs): - super().__init__(**kwargs) - - # common variables and references - self.parent = parent - self.resource = resource - - self.set_title(resource) - - # connect signals - self.btn_path.connect("clicked", self.__choose_path) - - def __choose_path(self, *_args): - """ - Open the file chooser dialog and set the path to the - selected file - """ - - def set_path(_dialog, response): - if response != Gtk.ResponseType.ACCEPT: - return - - path = dialog.get_file().get_path() - self.parent.add_resource(self.resource, path) - self.set_subtitle(path) - - dialog = Gtk.FileChooserNative.new( - title=_("Select Resource File"), - action=Gtk.FileChooserAction.OPEN, - parent=self.parent, - ) - - dialog.set_modal(True) - dialog.connect("response", set_path) - dialog.show() - - -@Gtk.Template(resource_path="/com/usebottles/bottles/installer-dialog.ui") -class InstallerDialog(Adw.Window): - __gtype_name__ = "InstallerDialog" - __sections = {} - __steps = 0 - __current_step = 0 - __local_resources = [] - __final_resources = {} - - # region widgets - stack = Gtk.Template.Child() - window_title = Gtk.Template.Child() - btn_install = Gtk.Template.Child() - btn_proceed = Gtk.Template.Child() - btn_close = Gtk.Template.Child() - status_init = Gtk.Template.Child() - status_installed = Gtk.Template.Child() - status_error = Gtk.Template.Child() - progressbar = Gtk.Template.Child() - group_resources = Gtk.Template.Child() - install_status_page = Gtk.Template.Child() - img_icon = Gtk.Template.Child() - img_icon_install = Gtk.Template.Child() - style_provider = Gtk.CssProvider() - - # endregion - - def __init__(self, window, config, installer, **kwargs): - super().__init__(**kwargs) - self.set_transient_for(window) - - self.window = window - self.manager = window.manager - self.config = config - self.installer = installer - - self.__steps_phrases = { - "deps": _("Installing Windows dependencies…"), - "params": _("Configuring the bottle…"), - "steps": _("Processing installer steps…"), - "exe": _("Installing the {}…".format(installer[1].get("Name"))), - "checks": _("Performing final checks…"), - } - - self.status_init.set_title(installer[1].get("Name")) - self.install_status_page.set_title( - _("Installing {0}…").format(installer[1].get("Name")) - ) - self.status_installed.set_description( - _("{0} is now available in the programs view.").format( - installer[1].get("Name") - ) - ) - self.__set_icon() - - self.btn_install.connect("clicked", self.__check_resources) - self.btn_proceed.connect("clicked", self.__install) - self.btn_close.connect("clicked", self.__close) - - def __set_icon(self): - try: - url = self.manager.installer_manager.get_icon_url(self.installer[0]) - if url is None: - self.img_icon.set_visible(False) - self.img_icon_install.set_visible(False) - return - - with urllib.request.urlopen(url) as res: - stream = Gio.MemoryInputStream.new_from_data(res.read(), None) - pixbuf = GdkPixbuf.Pixbuf.new_from_stream(stream, None) - self.img_icon.set_pixel_size(78) - self.img_icon.set_from_pixbuf(pixbuf) - self.img_icon_install.set_pixel_size(78) - self.img_icon_install.set_from_pixbuf(pixbuf) - except: - self.img_icon.set_visible(False) - self.img_icon_install.set_visible(False) - - def __check_resources(self, *_args): - self.__local_resources = self.manager.installer_manager.has_local_resources( - self.installer - ) - if len(self.__local_resources) == 0: - self.__install() - return - - for resource in self.__local_resources: - _entry = LocalResourceRow(self, resource) - GLib.idle_add(self.group_resources.add, _entry) - - self.btn_proceed.set_visible(True) - self.stack.set_visible_child_name("page_resources") - - def __install(self, *_args): - self.set_deletable(False) - self.stack.set_visible_child_name("page_install") - - @GtkUtils.run_in_main_loop - def set_status(result, error=False): - if result.ok: - return self.__installed() - _err = result.data.get("message", _("Installer failed with unknown error")) - self.__error(_err) - - self.set_steps(self.manager.installer_manager.count_steps(self.installer)) - - RunAsync( - task_func=self.manager.installer_manager.install, - callback=set_status, - config=self.config, - installer=self.installer, - step_fn=self.next_step, - local_resources=self.__final_resources, - ) - - def __installed(self): - self.set_deletable(False) - self.stack.set_visible_child_name("page_installed") - self.window.page_details.view_bottle.update_programs() - self.window.page_details.go_back_sidebar() - - def __error(self, error): - self.set_deletable(True) - self.status_error.set_description(error) - self.stack.set_visible_child_name("page_error") - - def next_step(self): - """Next step""" - phrase = self.__steps_phrases[self.__sections[self.__current_step]] - self.progressbar.set_text(phrase) - self.__current_step += 1 - self.progressbar.set_fraction(self.__current_step * (1 / self.__steps)) - - def set_steps(self, steps): - """Set steps""" - self.__steps = steps["total"] - self.__sections = steps["sections"] - - def add_resource(self, resource, path): - self.__final_resources[resource] = path - if len(self.__local_resources) == len(self.__final_resources): - self.btn_proceed.set_sensitive(True) - - def __close(self, *_args): - self.destroy() diff --git a/bottles/frontend/installer_row.py b/bottles/frontend/installer_row.py deleted file mode 100644 index 3e0d4906dfe..00000000000 --- a/bottles/frontend/installer_row.py +++ /dev/null @@ -1,106 +0,0 @@ -# installer_row.py -# -# Copyright 2025 The Bottles Contributors -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, in version 3 of the License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# - -from gi.repository import Gtk, Adw -from gettext import gettext as _ -import webbrowser - -from bottles.frontend.generic import SourceDialog -from bottles.frontend.installer_dialog import InstallerDialog - - -@Gtk.Template(resource_path="/com/usebottles/bottles/installer-row.ui") -class InstallerRow(Adw.ActionRow): - __gtype_name__ = "InstallerRow" - - # region Widgets - btn_install = Gtk.Template.Child() - btn_review = Gtk.Template.Child() - btn_manifest = Gtk.Template.Child() - btn_report = Gtk.Template.Child() - label_grade = Gtk.Template.Child() - - # endregion - - def __init__(self, window, config, installer, **kwargs): - super().__init__(**kwargs) - - # common variables and references - self.window = window - self.manager = window.manager - self.config = config - self.installer = installer - - grade_descriptions = { - "Bronze": _( - "This application may work poorly. The installer was configured to provide the best possible experience, but expect glitches, instability and lack of working features." - ), - "Silver": _( - "This program works with noticeable glitches, but these glitches do not affect the application's functionality." - ), - "Gold": _("This program works with minor glitches."), - "Platinum": _("This program works perfectly."), - } - - name = installer[1].get("Name") - description = installer[1].get("Description") - grade = installer[1].get("Grade") - grade_description = grade_descriptions[grade] - - # populate widgets - self.set_title(name) - self.set_subtitle(description) - self.label_grade.set_text(grade) - self.label_grade.get_style_context().add_class(f"grade-{grade}") - self.set_tooltip_text(grade_description) - - # connect signals - self.btn_install.connect("clicked", self.__execute_installer) - self.btn_manifest.connect("clicked", self.__open_manifest) - self.btn_review.connect("clicked", self.__open_review) - self.btn_report.connect("clicked", self.__open_bug_report) - - def __open_manifest(self, widget): - """Open installer manifest""" - plain_manifest = self.manager.installer_manager.get_installer( - installer_name=self.installer[0], plain=True - ) - SourceDialog( - parent=self.window, - title=_("Manifest for {0}").format(self.installer[0]), - message=plain_manifest, - ).present() - - def __open_review(self, widget): - """Open review""" - plain_text = self.manager.installer_manager.get_review( - self.installer[0], parse=False - ) - SourceDialog( - parent=self.window, - title=_("Review for {0}").format(self.installer[0]), - message=plain_text, - lang="markdown", - ).present() - - @staticmethod - def __open_bug_report(widget): - """Open bug report""" - webbrowser.open("https://github.com/bottlesdevs/programs/issues") - - def __execute_installer(self, widget): - InstallerDialog(self.window, self.config, self.installer).present() diff --git a/bottles/frontend/meson.build b/bottles/frontend/meson.build index bab61821996..a98e0a13563 100644 --- a/bottles/frontend/meson.build +++ b/bottles/frontend/meson.build @@ -15,7 +15,6 @@ blueprints = custom_target('blueprints', 'dependency-entry-row.blp', 'bottle-details-page.blp', 'details-dependencies-view.blp', - 'details-installers-view.blp', 'details-task-manager-view.blp', 'bottle-details-view.blp', 'bottle-picker-dialog.blp', @@ -26,7 +25,6 @@ blueprints = custom_target('blueprints', 'duplicate-dialog.blp', 'environment-variables-dialog.blp', 'gamescope-dialog.blp', - 'installer-dialog.blp', 'journal-dialog.blp', 'launch-options-dialog.blp', 'proton-alert-dialog.blp', @@ -42,7 +40,6 @@ blueprints = custom_target('blueprints', 'env-var-entry.blp', 'importer-row.blp', 'importer-view.blp', - 'installer-row.blp', 'library-entry.blp', 'library-view.blp', 'bottle-row.blp', @@ -100,14 +97,12 @@ bottles_sources = [ 'importer_view.py', 'loading_view.py', 'bottle_details_page.py', - 'details_installers_view.py', 'details_dependencies_view.py', 'details_preferences_page.py', 'details_task_manager_view.py', 'dependency_entry_row.py', 'executable.py', 'importer_row.py', - 'installer_row.py', 'program_row.py', 'component_entry_row.py', 'library_entry.py', @@ -130,7 +125,6 @@ bottles_sources = [ 'bottle_picker_dialog.py', 'proton_alert_dialog.py', 'sandbox_dialog.py', - 'installer_dialog.py', 'dependencies_check_dialog.py', 'vmtouch_dialog.py', 'window.py', From df71f9d59b68cce2e0b2a3a583b52560de3f646a Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Wed, 22 Jan 2025 22:37:48 -0500 Subject: [PATCH 106/146] backend: Remove InstallerManager --- bottles/backend/managers/installer.py | 453 -------------------------- bottles/backend/managers/manager.py | 17 - bottles/backend/managers/meson.build | 1 - 3 files changed, 471 deletions(-) delete mode 100644 bottles/backend/managers/installer.py diff --git a/bottles/backend/managers/installer.py b/bottles/backend/managers/installer.py deleted file mode 100644 index 218d98744b7..00000000000 --- a/bottles/backend/managers/installer.py +++ /dev/null @@ -1,453 +0,0 @@ -# installer_manager.py -# -# Copyright 2022 brombinmirko -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, in version 3 of the License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -import os -import subprocess -import uuid -from functools import lru_cache - -import markdown -import pycurl - -from bottles.backend.globals import Paths -from bottles.backend.logger import Logger -from bottles.backend.managers.conf import ConfigManager -from bottles.backend.models.config import BottleConfig -from bottles.backend.models.result import Result -from bottles.backend.utils.manager import ManagerUtils -from bottles.backend.utils.wine import WineUtils -from bottles.backend.repos.installer import InstallerRepo -from bottles.backend.wine.executor import WineExecutor -from bottles.backend.wine.winecommand import WineCommand - -logging = Logger() - - -class InstallerManager: - def __init__(self, manager): - self.__manager = manager - self.__local_resources = {} - - url = "https://proxy.usebottles.com/repo/programs/" - self.__repo = InstallerRepo(url, "") - - @lru_cache - def get_review(self, installer_name, parse: bool = True) -> str: - """Return an installer review from the repository (as HTML)""" - review = self.__repo.get_review(installer_name) - if not review: - return "No review found for this installer." - if parse: - return markdown.markdown(review) - return review - - @lru_cache - def get_installer( - self, installer_name: str, plain: bool = False - ) -> str | dict | bool: - """ - Return an installer manifest from the repository. Use the plain - argument to get the manifest as plain text. - """ - return self.__repo.get(installer_name, plain) - - @lru_cache - def fetch_catalog(self) -> dict: - """Fetch the installers catalog from the repository""" - catalog = {} - index = self.__repo.catalog - - for installer in index.items(): - catalog[installer[0]] = installer[1] - - catalog = dict(sorted(catalog.items())) - return catalog - - def get_icon_url(self, installer): - """Wrapper for the repo method.""" - return self.__repo.get_icon(installer) - - def __download_icon(self, config, executable: dict, manifest): - """ - Download the installer icon from the repository to the bottle - icons path. - """ - icon_url = self.__repo.get_icon(manifest.get("Name")) - bottle_icons_path = f"{ManagerUtils.get_bottle_path(config)}/icons" - icon_path = f"{bottle_icons_path}/{executable.get('icon')}" - - if icon_url is not None: - if not os.path.exists(bottle_icons_path): - os.makedirs(bottle_icons_path) - - if not os.path.isfile(icon_path): - c = pycurl.Curl() - c.setopt(c.URL, icon_url) - c.setopt(c.WRITEDATA, open(icon_path, "wb")) - c.perform() - c.close() - - def __process_local_resources(self, exe_msi_steps, installer): - files = self.has_local_resources(installer) - if not files: - return True - for file in files: - if file not in exe_msi_steps.keys(): - return False - self.__local_resources[file] = exe_msi_steps[file] - return True - - def __install_dependencies( - self, - config: BottleConfig, - dependencies: list, - step_fn: callable, - is_final: bool = False, - ): - """Install a list of dependencies""" - _config = config - - for dep in dependencies: - if is_final: - step_fn() - - if dep in config.Installed_Dependencies: - continue - - _dep = [dep, self.__manager.supported_dependencies.get(dep)] - res = self.__manager.dependency_manager.install(_config, _dep) - - if not res.ok: - return False - - return True - - @staticmethod - def __perform_checks(config, checks: dict): - """Perform a list of checks""" - bottle_path = ManagerUtils.get_bottle_path(config) - - if files := checks.get("files"): - for f in files: - if f.startswith("userdir/"): - current_user = os.getenv("USER") - f = f.replace("userdir/", f"users/{current_user}/") - - _f = os.path.join(bottle_path, "drive_c", f) - if not os.path.exists(_f): - logging.error( - f"During checks, file {_f} was not found, assuming it is not installed. Aborting." - ) - return False - - return True - - def __perform_steps(self, config: BottleConfig, steps: list): - """Perform a list of actions""" - for st in steps: - # Step type: run_script - if st.get("action") == "run_script": - self.__step_run_script(config, st) - - # Step type: run_winecommand - if st.get("action") == "run_winecommand": - self.__step_run_winecommand(config, st) - - # Step type: update_config - if st.get("action") == "update_config": - self.__step_update_config(config, st) - - return True - - @staticmethod - def __step_run_winecommand(config: BottleConfig, step: dict): - """Run a wine command""" - commands = step.get("commands") - - if not commands: - return - - for command in commands: - _winecommand = WineCommand( - config, - command=command.get("command"), - arguments=command.get("arguments"), - minimal=command.get("minimal"), - ) - _winecommand.run() - - @staticmethod - def __step_run_script(config: BottleConfig, step: dict): - placeholders = { - "!bottle_path": ManagerUtils.get_bottle_path(config), - "!bottle_drive": f"{ManagerUtils.get_bottle_path(config)}/drive_c", - "!bottle_name": config.Name, - "!bottle_arch": config.Arch, - } - preventions = {"bottle.yml": "Bottle configuration cannot be modified."} - script = step.get("script") - - for key, value in placeholders.items(): - script = script.replace(key, value) - - for key, value in preventions.items(): - if script.find(key) != -1: - logging.error( - value, - ) - return False - - logging.info("Executing installer script…") - subprocess.Popen( - f"bash -c '{script}'", - shell=True, - cwd=ManagerUtils.get_bottle_path(config), - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - ).communicate() - logging.info("Finished executing installer script.") - - @staticmethod - def __step_update_config(config: BottleConfig, step: dict): - bottle = ManagerUtils.get_bottle_path(config) - conf_path = step.get("path") - conf_type = step.get("type") - del_keys = step.get("del_keys", {}) - upd_keys = step.get("upd_keys", {}) - - if conf_path.startswith("userdir/"): - current_user = os.getenv("USER") - conf_path = conf_path.replace("userdir/", f"drive_c/users/{current_user}/") - - conf_path = f"{bottle}/{conf_path}" - _conf = ConfigManager(config_file=conf_path, config_type=conf_type) - - for d in del_keys: - _conf.del_key(d) - - _conf.merge_dict(upd_keys) - - def __set_parameters(self, config: BottleConfig, new_params: dict): - _config = config - - if "dxvk" in new_params and isinstance(new_params["dxvk"], bool): - if new_params["dxvk"] != config.Parameters.dxvk: - self.__manager.install_dll_component( - _config, "dxvk", remove=not new_params["dxvk"] - ) - - if "vkd3d" in new_params and isinstance(new_params["vkd3d"], bool): - if new_params["vkd3d"] != config.Parameters.vkd3d: - self.__manager.install_dll_component( - _config, "vkd3d", remove=not new_params["vkd3d"] - ) - - if "dxvk_nvapi" in new_params and isinstance(new_params["dxvk_nvapi"], bool): - if new_params["dxvk_nvapi"] != config.Parameters.dxvk_nvapi: - self.__manager.install_dll_component( - _config, "nvapi", remove=not new_params["dxvk_nvapi"] - ) - - if "latencyflex" in new_params and isinstance(new_params["latencyflex"], bool): - if new_params["latencyflex"] != config.Parameters.latencyflex: - self.__manager.install_dll_component( - _config, "latencyflex", remove=not new_params["latencyflex"] - ) - - # avoid sync type change if not set to "wine" - if "sync" in new_params and config.Parameters.sync != "wine": - del new_params["sync"] - - for k, v in new_params.items(): - self.__manager.update_config( - config=config, key=k, value=v, scope="Parameters" - ) - - def count_steps(self, installer) -> dict: - manifest = self.get_installer(installer[0]) - steps = {"total": 0, "sections": []} - if manifest.get("Dependencies"): - i = int(len(manifest.get("Dependencies"))) - steps["sections"] += i * ["deps"] - steps["total"] += i - if manifest.get("Parameters"): - steps["sections"].append("params") - steps["total"] += 1 - if manifest.get("Steps"): - i = int(len(manifest.get("Steps"))) - steps["sections"] += i * ["steps"] - steps["total"] += i - if manifest.get("Executable"): - steps["sections"].append("exe") - steps["total"] += 1 - if manifest.get("Checks"): - steps["sections"].append("checks") - steps["total"] += 1 - - return steps - - def has_local_resources(self, installer): - manifest = self.get_installer(installer[0]) - steps = manifest.get("Steps", []) - exe_msi_steps = [ - s - for s in steps - if s.get("action", "") in ["install_exe", "install_msi"] - and s.get("url", "") == "local" - ] - - if len(exe_msi_steps) == 0: - return [] - - files = [s.get("file_name", "") for s in exe_msi_steps] - return files - - def install( - self, - config: BottleConfig, - installer: dict, - step_fn: callable, - is_final: bool = True, - local_resources: dict | None = None, - ): - manifest = self.get_installer(installer[0]) - _config = config - - bottle = ManagerUtils.get_bottle_path(config) - installers = manifest.get("Installers") - dependencies = manifest.get("Dependencies") - parameters = manifest.get("Parameters") - executable = manifest.get("Executable") - steps = manifest.get("Steps") - checks = manifest.get("Checks") - - # download icon - if executable.get("icon"): - self.__download_icon(_config, executable, manifest) - - # install dependent installers - if installers: - logging.info("Installing dependent installers") - for i in installers: - if not self.install(config, i, step_fn, False): - logging.error("Failed to install dependent installer(s)") - return Result( - False, - data={"message": "Failed to install dependent installer(s)"}, - ) - - # ask for local resources - if local_resources: - if not self.__process_local_resources(local_resources, installer): - return Result( - False, data={"message": "Local resources not found or invalid"} - ) - - # install dependencies - if dependencies: - logging.info("Installing dependencies") - if not self.__install_dependencies( - _config, dependencies, step_fn, is_final - ): - return Result( - False, data={"message": "Dependencies installation failed."} - ) - - # set parameters - if parameters: - logging.info("Updating bottle parameters") - if is_final: - step_fn() - - self.__set_parameters(_config, parameters) - - # execute steps - if steps: - logging.info("Executing installer steps") - if is_final: - step_fn() - - if not self.__perform_steps(_config, steps): - return Result( - False, data={"message": "Installer is not well configured."} - ) - - # execute checks - if checks: - logging.info("Executing installer checks") - if is_final: - step_fn() - if not self.__perform_checks(_config, checks): - return Result( - False, - data={ - "message": "Checks failed, the program is not installed." - }, - ) - - # register executable - if executable["path"].startswith("userdir/"): - _userdir = WineUtils.get_user_dir(bottle) - executable["path"] = executable["path"].replace( - "userdir/", f"/users/{_userdir}/" - ) - - _path = f'C:\\{executable["path"]}'.replace("/", "\\") - _uuid = str(uuid.uuid4()) - _program = { - "executable": executable["file"], - "arguments": executable.get("arguments", ""), - "name": executable["name"], - "path": _path, - "id": _uuid, - } - - if "dxvk" in executable: - _program["dxvk"] = executable["dxvk"] - if "vkd3d" in executable: - _program["vkd3d"] = executable["vkd3d"] - if "dxvk_nvapi" in executable: - _program["dxvk_nvapi"] = executable["dxvk_nvapi"] - - duplicates = [ - k for k, v in config.External_Programs.items() if v["path"] == _path - ] - ext = config.External_Programs - - if duplicates: - for d in duplicates: - del ext[d] - ext[_uuid] = _program - self.__manager.update_config( - config=config, key="External_Programs", value=ext - ) - else: - self.__manager.update_config( - config=config, key=_uuid, value=_program, scope="External_Programs" - ) - - # create Desktop entry - bottles_icons_path = os.path.join(ManagerUtils.get_bottle_path(config), "icons") - icon_path = os.path.join(bottles_icons_path, executable.get("icon")) - ManagerUtils.create_desktop_entry(_config, _program, False, icon_path) - - if is_final: - step_fn() - - logging.info( - f"Program installed: {manifest['Name']} in {config.Name}.", jn=True - ) - return Result(True) diff --git a/bottles/backend/managers/manager.py b/bottles/backend/managers/manager.py index 18e3a7cdaf6..ff18ff7a81c 100644 --- a/bottles/backend/managers/manager.py +++ b/bottles/backend/managers/manager.py @@ -40,7 +40,6 @@ from bottles.backend.managers.dependency import DependencyManager from bottles.backend.managers.epicgamesstore import EpicGamesStoreManager from bottles.backend.managers.importer import ImportManager -from bottles.backend.managers.installer import InstallerManager from bottles.backend.managers.library import LibraryManager from bottles.backend.managers.template import TemplateManager from bottles.backend.managers.ubisoftconnect import UbisoftConnectManager @@ -123,7 +122,6 @@ def __init__( ) # sub-managers - self.installer_manager = InstallerManager(self) self.dependency_manager = DependencyManager(self) self.import_manager = ImportManager(self) times["ImportManager"] = time.time() @@ -173,8 +171,6 @@ def checks(self, install_latest=False, first_run=False) -> Result: self.organize_dependencies() - self.organize_installers() - self.check_bottles() rv.data["check_bottles"] = time.time() @@ -205,19 +201,6 @@ def organize_dependencies(self): self.supported_dependencies = catalog EventManager.done(Events.DependenciesOrganizing) - @RunAsync.run_async - def organize_installers(self): - """Organizes installers into supported_installers.""" - EventManager.wait(Events.InstallersFetching) - catalog = self.installer_manager.fetch_catalog() - if len(catalog) == 0: - EventManager.done(Events.InstallersOrganizing) - logging.info("No installers found!") - return - - self.supported_installers = catalog - EventManager.done(Events.InstallersOrganizing) - def remove_dependency(self, config: BottleConfig, dependency: list): """Uninstall a dependency and remove it from the bottle config.""" dependency = dependency[0] diff --git a/bottles/backend/managers/meson.build b/bottles/backend/managers/meson.build index afcf2f24743..d22590c7777 100644 --- a/bottles/backend/managers/meson.build +++ b/bottles/backend/managers/meson.build @@ -5,7 +5,6 @@ bottles_sources = [ '__init__.py', 'backup.py', 'dependency.py', - 'installer.py', 'library.py', 'manager.py', 'data.py', From 7bf6724fc140005c3d1733bb56b12e4ad78e03ac Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Wed, 22 Jan 2025 22:47:15 -0500 Subject: [PATCH 107/146] backend: Remove DataManager --- bottles/backend/managers/data.py | 101 --------------------------- bottles/backend/managers/manager.py | 12 ---- bottles/backend/managers/meson.build | 1 - bottles/frontend/preferences.py | 30 +------- bottles/frontend/window.py | 15 ---- 5 files changed, 1 insertion(+), 158 deletions(-) delete mode 100644 bottles/backend/managers/data.py diff --git a/bottles/backend/managers/data.py b/bottles/backend/managers/data.py deleted file mode 100644 index fc463840ca4..00000000000 --- a/bottles/backend/managers/data.py +++ /dev/null @@ -1,101 +0,0 @@ -# data.py -# -# Copyright 2022 brombinmirko -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, in version 3 of the License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# - -import contextlib -import os - -from bottles.backend.globals import Paths -from bottles.backend.logger import Logger -from bottles.backend.models.samples import Samples -from bottles.backend.utils import yaml - -logging = Logger() - - -class UserDataKeys: - CustomBottlesPath = "custom_bottles_path" - - -class DataManager: - """ - The DataManager class is used to store and retrieve data - from the user data.yml file. Should be stored only info - and settings that should not be stored in gsettings. - """ - - __data: dict = {} - __p_data = f"{Paths.base}/data.yml" - - def __init__(self): - self.__get_data() - - def __get_data(self): - try: - with open(self.__p_data) as s: - self.__data = yaml.load(s) - if self.__data is None: - raise AttributeError - except FileNotFoundError: - logging.error( - "Data file not found. Creating new one.", - ) - self.__create_data_file() - except AttributeError: - logging.error( - "Data file is empty. Creating new one.", - ) - self.__create_data_file() - - def __create_data_file(self): - if not os.path.exists(Paths.base): - os.makedirs(Paths.base) - with open(self.__p_data, "w") as s: - yaml.dump(Samples.data, s) - self.__get_data() - - def list(self): - """Returns the whole data dictionary.""" - return self.__data - - def set(self, key, value, of_type=None): - """Sets a value in the data dictionary.""" - if self.__data.get(key): - if isinstance(self.__data[key], list): - self.__data[key].append(value) - else: - self.__data[key] = value - else: - if of_type is list: - self.__data[key] = [value] - else: - self.__data[key] = value - - with contextlib.suppress(FileNotFoundError): - with open(self.__p_data, "w") as s: - yaml.dump(self.__data, s) - - def remove(self, key): - """Removes a key from the data dictionary.""" - if self.__data.get(key): - del self.__data[key] - with contextlib.suppress(FileNotFoundError): - with open(self.__p_data, "w") as s: - yaml.dump(self.__data, s) - - def get(self, key): - """Returns the value of a key in the data dictionary.""" - return self.__data.get(key) diff --git a/bottles/backend/managers/manager.py b/bottles/backend/managers/manager.py index ff18ff7a81c..174c2b33362 100644 --- a/bottles/backend/managers/manager.py +++ b/bottles/backend/managers/manager.py @@ -36,7 +36,6 @@ from bottles.backend.dlls.vkd3d import VKD3DComponent from bottles.backend.globals import Paths from bottles.backend.logger import Logger -from bottles.backend.managers.data import DataManager, UserDataKeys from bottles.backend.managers.dependency import DependencyManager from bottles.backend.managers.epicgamesstore import EpicGamesStoreManager from bottles.backend.managers.importer import ImportManager @@ -108,19 +107,8 @@ def __init__( # common variables self.settings = g_settings or GSettingsStub - self.data_mgr = DataManager() _offline = False - # validating user-defined Paths.bottles - if user_bottles_path := self.data_mgr.get(UserDataKeys.CustomBottlesPath): - if os.path.exists(user_bottles_path): - Paths.bottles = user_bottles_path - else: - logging.error( - f"Custom bottles path {user_bottles_path} does not exist! " - f"Falling back to default path." - ) - # sub-managers self.dependency_manager = DependencyManager(self) self.import_manager = ImportManager(self) diff --git a/bottles/backend/managers/meson.build b/bottles/backend/managers/meson.build index d22590c7777..7fd361cece9 100644 --- a/bottles/backend/managers/meson.build +++ b/bottles/backend/managers/meson.build @@ -7,7 +7,6 @@ bottles_sources = [ 'dependency.py', 'library.py', 'manager.py', - 'data.py', 'runtime.py', 'importer.py', 'conf.py', diff --git a/bottles/frontend/preferences.py b/bottles/frontend/preferences.py index c30e23af873..af60bfd6c24 100644 --- a/bottles/frontend/preferences.py +++ b/bottles/frontend/preferences.py @@ -22,7 +22,7 @@ from gi.repository import Gtk, Adw, Gio, GLib -from bottles.backend.managers.data import DataManager, UserDataKeys +from bottles.backend.globals import Paths from bottles.backend.state import EventManager, Events from bottles.backend.utils.threading import RunAsync from bottles.backend.utils.generic import sort_by_version @@ -77,16 +77,8 @@ def __init__(self, window, **kwargs): self.window = window self.settings = window.settings self.manager = window.manager - self.data = DataManager() self.style_manager = Adw.StyleManager.get_default() - self.current_bottles_path = self.data.get(UserDataKeys.CustomBottlesPath) - if self.current_bottles_path: - self.label_bottles_path.set_label( - os.path.basename(self.current_bottles_path) - ) - self.btn_bottles_path_reset.set_visible(True) - # bind widgets self.settings.bind( "dark-theme", self.switch_theme, "active", Gio.SettingsBindFlags.DEFAULT @@ -214,7 +206,6 @@ def set_path(_dialog, response): path = dialog.get_file().get_path() - self.data.set(UserDataKeys.CustomBottlesPath, path) self.label_bottles_path.set_label(os.path.basename(path)) self.btn_bottles_path_reset.set_visible(True) self.prompt_restart() @@ -235,28 +226,9 @@ def handle_restart(self, widget, response_id): self.window.proper_close() widget.destroy() - def prompt_restart(self): - if self.current_bottles_path != self.data.get(UserDataKeys.CustomBottlesPath): - dialog = Adw.MessageDialog.new( - self.window, - _("Relaunch Bottles?"), - _( - "Bottles will need to be relaunched to use this directory.\n\nBe sure to close every program launched from Bottles before relaunching Bottles, as not doing so can cause data loss, corruption and programs to malfunction." - ), - ) - dialog.add_response("dismiss", _("_Cancel")) - dialog.add_response("restart", _("_Relaunch")) - dialog.set_response_appearance( - "restart", Adw.ResponseAppearance.DESTRUCTIVE - ) - dialog.connect("response", self.handle_restart) - dialog.present() - def __reset_bottles_path(self, widget): - self.data.remove(UserDataKeys.CustomBottlesPath) self.btn_bottles_path_reset.set_visible(False) self.label_bottles_path.set_label(_("(Default)")) - self.prompt_restart() def __display_unstable_candidate(self, component=["", {"Channel": "unstable"}]): return self.window.settings.get_boolean("release-candidate") or component[1][ diff --git a/bottles/frontend/window.py b/bottles/frontend/window.py index fe82e7c6c8c..f6e8a344c34 100644 --- a/bottles/frontend/window.py +++ b/bottles/frontend/window.py @@ -25,7 +25,6 @@ from bottles.backend.globals import Paths from bottles.backend.health import HealthChecker from bottles.backend.logger import Logger -from bottles.backend.managers.data import UserDataKeys from bottles.backend.managers.manager import Manager from bottles.backend.models.config import BottleConfig from bottles.backend.models.result import Result @@ -248,20 +247,6 @@ def set_manager(result: Manager, error=None): self.lock_ui(False) self.headerbar.get_style_context().remove_class("flat") - user_defined_bottles_path = self.manager.data_mgr.get( - UserDataKeys.CustomBottlesPath - ) - if user_defined_bottles_path and Paths.bottles != user_defined_bottles_path: - dialog = Adw.MessageDialog.new( - self, - _("Custom Bottles Path not Found"), - _( - "Falling back to default path. No bottles from the given path will be listed." - ), - ) - dialog.add_response("cancel", _("_Dismiss")) - dialog.present() - def get_manager(): # do not redo connection if aborted connection mng = Manager(g_settings=self.settings) From af8e0e04bf5797eee0b1011045906e4636e932e0 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Wed, 22 Jan 2025 22:52:51 -0500 Subject: [PATCH 108/146] backend: Remove DependencyManager --- bottles/backend/managers/dependency.py | 508 ------------------------- bottles/backend/managers/manager.py | 49 --- bottles/backend/managers/meson.build | 1 - 3 files changed, 558 deletions(-) delete mode 100644 bottles/backend/managers/dependency.py diff --git a/bottles/backend/managers/dependency.py b/bottles/backend/managers/dependency.py deleted file mode 100644 index 73b9b19e9d1..00000000000 --- a/bottles/backend/managers/dependency.py +++ /dev/null @@ -1,508 +0,0 @@ -# dependency.py -# -# Copyright 2022 brombinmirko -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, in version 3 of the License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# - -import os -import shutil -from functools import lru_cache -from glob import glob - -import patoolib # type: ignore [import-untyped] - -from bottles.backend.cabextract import CabExtract -from bottles.backend.globals import Paths -from bottles.backend.logger import Logger -from bottles.backend.models.config import BottleConfig -from bottles.backend.models.enum import Arch -from bottles.backend.models.result import Result -from bottles.backend.state import TaskManager, Task -from bottles.backend.utils.manager import ManagerUtils -from bottles.backend.wine.executor import WineExecutor -from bottles.backend.wine.reg import Reg, RegItem -from bottles.backend.wine.regkeys import RegKeys -from bottles.backend.wine.regsvr32 import Regsvr32 -from bottles.backend.wine.uninstaller import Uninstaller -from bottles.backend.wine.winedbg import WineDbg -from bottles.backend.repos.dependency import DependencyRepo - -logging = Logger() - - -class DependencyManager: - def __init__(self, manager): - self.__manager = manager - - url = "https://proxy.usebottles.com/repo/dependencies/" - self.__repo = DependencyRepo(url, "") - - @lru_cache - def get_dependency(self, name: str, plain: bool = False) -> str | dict | bool: - return self.__repo.get(name, plain) - - @lru_cache - def fetch_catalog(self) -> dict: - """ - Fetch all dependencies from the Bottles repository - and return these as a dictionary. It also returns an empty dictionary - if there are no dependencies or fails to fetch them. - """ - - catalog = {} - index = self.__repo.catalog - - for dependency in index.items(): - catalog[dependency[0]] = dependency[1] - - catalog = dict(sorted(catalog.items())) - return catalog - - def install(self, config: BottleConfig, dependency: list) -> Result: - """ - Install a given dependency in a bottle. It will - return True if the installation was successful. - """ - uninstaller = True - - task_id = TaskManager.add(Task(title=dependency[0])) - - logging.info( - "Installing dependency [{}] in bottle [{}].".format( - dependency[0], config.Name - ), - ) - manifest = self.get_dependency(dependency[0]) - if not manifest: - """ - If the manifest is not found, return a Result - object with the error. - """ - TaskManager.remove(task_id) - return Result( - status=False, message=f"Cannot find manifest for {dependency[0]}." - ) - - if manifest.get("Dependencies"): - """ - If the manifest has dependencies, we need to install them - before installing the current one. - """ - for _ext_dep in manifest.get("Dependencies"): - if _ext_dep in config.Installed_Dependencies: - continue - if _ext_dep in self.__manager.supported_dependencies: - _dep = self.__manager.supported_dependencies[_ext_dep] - _res = self.install(config, [_ext_dep, _dep]) - if not _res.status: - return _res - - for step in manifest.get("Steps"): - """ - Here we execute all steps in the manifest. - Steps are the actions performed to install the dependency. - """ - arch = step.get("for", "win64_win32") - if config.Arch not in arch: - continue - - res = self.__perform_steps(config, step) - if not res.ok: - TaskManager.remove(task_id) - return Result( - status=False, - message=f"One or more steps failed for {dependency[0]}.", - ) - if not res.data.get("uninstaller"): - uninstaller = False - - if dependency[0] not in config.Installed_Dependencies: - """ - If the dependency is not already listed in the installed - dependencies list of the bottle, add it. - """ - dependencies = [dependency[0]] - - if config.Installed_Dependencies: - dependencies = config.Installed_Dependencies + [dependency[0]] - - self.__manager.update_config( - config=config, key="Installed_Dependencies", value=dependencies - ) - - if manifest.get("Uninstaller"): - """ - If the manifest has an uninstaller, add it to the - uninstaller list in the bottle config. - Set it to NO_UNINSTALLER if the dependency cannot be uninstalled. - """ - uninstaller = manifest.get("Uninstaller") - - if dependency[0] not in config.Installed_Dependencies: - self.__manager.update_config( - config, dependency[0], uninstaller, "Uninstallers" - ) - - # Remove entry from task manager - TaskManager.remove(task_id) - - # Hide installation button and show remove button - logging.info(f"Dependency installed: {dependency[0]} in {config.Name}", jn=True) - if not uninstaller: - return Result(status=True, data={"uninstaller": False}) - return Result(status=True, data={"uninstaller": True}) - - def __perform_steps(self, config: BottleConfig, step: dict) -> Result: - """ - This method execute a step in the bottle (e.g. changing the Windows - version, installing fonts, etc.) - --- - Returns True if the dependency cannot be uninstalled. - """ - uninstaller = True - - if step["action"] == "delete_dlls": - self.__step_delete_dlls(config, step) - - if step["action"] == "uninstall": - self.__step_uninstall(config=config, file_name=step["file_name"]) - - if step["action"] == "cab_extract": - uninstaller = False - if not self.__step_cab_extract(step=step): - return Result(status=False) - - if step["action"] == "get_from_cab": - uninstaller = False - if not self.__step_get_from_cab(config=config, step=step): - return Result(status=False) - - if step["action"] in ["install_cab_fonts", "install_fonts"]: - uninstaller = False - if not self.__step_install_fonts(config=config, step=step): - return Result(status=False) - - if step["action"] in ["copy_dll", "copy_file"]: - uninstaller = False - if not self.__step_copy_dll(config=config, step=step): - return Result(status=False) - - if step["action"] == "register_dll": - self.__step_register_dll(config=config, step=step) - - if step["action"] == "override_dll": - self.__step_override_dll(config=config, step=step) - - if step["action"] == "set_register_key": - self.__step_set_register_key(config=config, step=step) - - if step["action"] == "register_font": - self.__step_register_font(config=config, step=step) - - if step["action"] == "replace_font": - self.__step_replace_font(config=config, step=step) - - if step["action"] == "set_windows": - self.__step_set_windows(config=config, step=step) - - if step["action"] == "use_windows": - self.__step_use_windows(config=config, step=step) - - return Result(status=True, data={"uninstaller": uninstaller}) - - @staticmethod - def __get_real_dest(config: BottleConfig, dest: str) -> str | bool: - """This function return the real destination path.""" - bottle = ManagerUtils.get_bottle_path(config) - _dest = dest - - if dest.startswith("temp/"): - dest = dest.replace("temp/", f"{Paths.temp}/") - elif dest.startswith("windows/"): - dest = f"{bottle}/drive_c/{dest}" - elif dest.startswith("win32"): - dest = f"{bottle}/drive_c/windows/system32/" - if config.Arch == Arch.WIN64: - dest = f"{bottle}/drive_c/windows/syswow64/" - dest = _dest.replace("win32", dest) - elif dest.startswith("win64"): - if config.Arch == Arch.WIN64: - dest = f"{bottle}/drive_c/windows/system32/" - dest = _dest.replace("win64", dest) - else: - return True - else: - logging.error("Destination path not supported!") - return False - - return dest - - @staticmethod - def __step_uninstall(config: BottleConfig, file_name: str) -> bool: - """ - This function find an uninstaller in the bottle by the given - file name and execute it. - """ - Uninstaller(config).from_name(file_name) - return True - - def __step_cab_extract(self, step: dict): - """ - This function download and extract a Windows Cabinet to the - temp folder. - """ - dest = step.get("dest") - if dest.startswith("temp/"): - dest = dest.replace("temp/", f"{Paths.temp}/") - else: - logging.error("Destination path not supported!") - return False - - if step["url"].startswith("temp/"): - path = step["url"] - path = path.replace("temp/", f"{Paths.temp}/") - - if step.get("rename"): - file_path = os.path.splitext(f"{step.get('rename')}")[0] - else: - file_path = os.path.splitext(f"{step.get('file_name')}")[0] - - if not CabExtract().run( - f"{path}/{step.get('file_name')}", file_path, destination=dest - ): - return False - - return True - - def __step_delete_dlls(self, config: BottleConfig, step: dict): - """Deletes the given dlls from the system32 or syswow64 paths""" - dest = self.__get_real_dest(config, step.get("dest")) - - for d in step.get("dlls", []): - _d = os.path.join(dest, d) - if os.path.exists(_d): - os.remove(_d) - - return True - - def __step_get_from_cab(self, config: BottleConfig, step: dict): - """Take a file from a cabiner and extract to a path.""" - source = step.get("source") - file_name = step.get("file_name") - rename = step.get("rename") - dest = self.__get_real_dest(config, step.get("dest")) - - if isinstance(dest, bool): - return dest - - res = CabExtract().run( - path=os.path.join(Paths.temp, source), files=[file_name], destination=dest - ) - - if rename: - _file_name = file_name.split("/")[-1] - - if os.path.exists(os.path.join(dest, rename)): - os.remove(os.path.join(dest, rename)) - - shutil.move(os.path.join(dest, _file_name), os.path.join(dest, rename)) - - if not res: - return False - return True - - @staticmethod - def __step_install_fonts(config: BottleConfig, step: dict): - """Move fonts to the drive_c/windows/Fonts path.""" - path = step["url"] - path = path.replace("temp/", f"{Paths.temp}/") - bottle_path = ManagerUtils.get_bottle_path(config) - - for font in step.get("fonts"): - font_path = f"{bottle_path}/drive_c/windows/Fonts/" - if not os.path.exists(font_path): - os.makedirs(font_path) - - try: - shutil.copyfile(f"{path}/{font}", f"{font_path}/{font}") - except (FileNotFoundError, FileExistsError): - logging.warning(f"Font {font} already exists or is not found.") - - # print(f"Copying {font} to {bottle_path}/drive_c/windows/Fonts/") - - return True - - # noinspection PyTypeChecker - def __step_copy_dll(self, config: BottleConfig, step: dict): - """ - This function copy dlls from temp folder to a directory - declared in the step. The bottle drive_c path will be used as - root path. - """ - path = step["url"] - path = path.replace("temp/", f"{Paths.temp}/") - dest = self.__get_real_dest(config, step.get("dest")) - - if isinstance(dest, bool): - return dest - - if not os.path.exists(dest): - os.makedirs(dest) - - try: - if "*" in step.get("file_name"): - files = glob(f"{path}/{step.get('file_name')}") - if not files: - logging.info(f"File(s) not found in {path}") - return False - for fg in files: - _name = fg.split("/")[-1] - _path = os.path.join(path, _name) - _dest = os.path.join(dest, _name) - logging.info(f"Copying {_name} to {_dest}") - - if os.path.exists(_dest) and os.path.islink(_dest): - os.unlink(_dest) - - try: - shutil.copyfile(_path, _dest) - except shutil.SameFileError: - logging.info( - f"{_name} already exists at the same version, skipping." - ) - else: - _name = step.get("file_name") - _dest = os.path.join(dest, _name) - logging.info(f"Copying {_name} to {_dest}") - - if os.path.exists(_dest) and os.path.islink(_dest): - os.unlink(_dest) - - try: - shutil.copyfile(os.path.join(path, _name), _dest) - except shutil.SameFileError: - logging.info( - f"{_name} already exists at the same version, skipping." - ) - - except Exception as e: - print(e) - logging.warning("An error occurred while copying dlls.") - return False - - return True - - @staticmethod - def __step_register_dll(config: BottleConfig, step: dict): - """Register one or more dll and ActiveX control""" - regsvr32 = Regsvr32(config) - - for dll in step.get("dlls", []): - regsvr32.register(dll) - - return True - - @staticmethod - def __step_override_dll(config: BottleConfig, step: dict): - """Register a new override for each dll.""" - reg = Reg(config) - - if step.get("url") and step.get("url").startswith("temp/"): - path = step["url"].replace("temp/", f"{Paths.temp}/") - dlls = glob(os.path.join(path, step.get("dll"))) - - bundle = {"HKEY_CURRENT_USER\\Software\\Wine\\DllOverrides": []} - - for dll in dlls: - dll_name = os.path.splitext(os.path.basename(dll))[0] - bundle["HKEY_CURRENT_USER\\Software\\Wine\\DllOverrides"].append( - {"value": dll_name, "data": step.get("type")} - ) - - reg.import_bundle(bundle) - return True - - if step.get("bundle"): - _bundle = { - "HKEY_CURRENT_USER\\Software\\Wine\\DllOverrides": step.get("bundle") - } - reg.import_bundle(_bundle) - return True - - reg.add( - key="HKEY_CURRENT_USER\\Software\\Wine\\DllOverrides", - value=step.get("dll"), - data=step.get("type"), - ) - return True - - @staticmethod - def __step_set_register_key(config: BottleConfig, step: dict): - """Set a registry key.""" - reg = Reg(config) - reg.add( - key=step.get("key"), - value=step.get("value"), - data=step.get("data"), - value_type=step.get("type"), - ) - return True - - @staticmethod - def __step_register_font(config: BottleConfig, step: dict): - """Register a font in the registry.""" - reg = Reg(config) - reg.add( - key="HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts", - value=step.get("name"), - data=step.get("file"), - ) - return True - - @staticmethod - def __step_replace_font(config: BottleConfig, step: dict): - """Register a font replacement in the registry.""" - reg = Reg(config) - target_font = step.get("font") - replaces = step.get("replace") - - if not isinstance(replaces, list): - logging.warning("Invalid replace_font, 'replace' field should be list.") - return False - - regs = [ - RegItem( - key="HKEY_CURRENT_USER\\Software\\Wine\\Fonts\\Replacements", - value=r, - value_type="", - data=target_font, - ) - for r in replaces - ] - reg.bulk_add(regs) - return True - - @staticmethod - def __step_set_windows(config: BottleConfig, step: dict): - """Set the Windows version.""" - rk = RegKeys(config) - rk.lg_set_windows(step.get("version")) - return True - - @staticmethod - def __step_use_windows(config: BottleConfig, step: dict): - """Set a Windows version per program.""" - rk = RegKeys(config) - rk.set_app_default(step.get("version"), step.get("executable")) - return True diff --git a/bottles/backend/managers/manager.py b/bottles/backend/managers/manager.py index 174c2b33362..7ac90047bad 100644 --- a/bottles/backend/managers/manager.py +++ b/bottles/backend/managers/manager.py @@ -36,7 +36,6 @@ from bottles.backend.dlls.vkd3d import VKD3DComponent from bottles.backend.globals import Paths from bottles.backend.logger import Logger -from bottles.backend.managers.dependency import DependencyManager from bottles.backend.managers.epicgamesstore import EpicGamesStoreManager from bottles.backend.managers.importer import ImportManager from bottles.backend.managers.library import LibraryManager @@ -110,7 +109,6 @@ def __init__( _offline = False # sub-managers - self.dependency_manager = DependencyManager(self) self.import_manager = ImportManager(self) times["ImportManager"] = time.time() @@ -157,8 +155,6 @@ def checks(self, install_latest=False, first_run=False) -> Result: self.check_runners(install_latest) or rv.set_status(False) rv.data["check_runners"] = time.time() - self.organize_dependencies() - self.check_bottles() rv.data["check_bottles"] = time.time() @@ -176,19 +172,6 @@ def check_app_dirs(self): """ map(lambda path: os.makedirs(path, exist_ok=True), Paths.get_components_paths()) - @RunAsync.run_async - def organize_dependencies(self): - """Organizes dependencies into supported_dependencies.""" - EventManager.wait(Events.DependenciesFetching) - catalog = self.dependency_manager.fetch_catalog() - if len(catalog) == 0: - EventManager.done(Events.DependenciesOrganizing) - logging.info("No dependencies found!") - return - - self.supported_dependencies = catalog - EventManager.done(Events.DependenciesOrganizing) - def remove_dependency(self, config: BottleConfig, dependency: list): """Uninstall a dependency and remove it from the bottle config.""" dependency = dependency[0] @@ -893,19 +876,6 @@ def create_bottle_from_config(self, config: BottleConfig) -> bool: """ self.install_dll_component(config, "vkd3d") - for dependency in config.Installed_Dependencies: - """ - Install each declared dependency in the new bottle. - """ - if dependency in self.supported_dependencies.keys(): - dep = [dependency, self.supported_dependencies[dependency]] - res = self.dependency_manager.install(config, dep) - if not res.ok: - logging.error( - _("Failed to install dependency: %s") % dependency, - jn=True, - ) - return False logging.info(f"New bottle from config created: {config.Path}") self.update_bottles(silent=True) return True @@ -1231,25 +1201,6 @@ def components_check(): for dep in env.get("Installed_Dependencies", []): if template and dep in template["config"]["Installed_Dependencies"]: continue - if dep in self.supported_dependencies: - _dep = self.supported_dependencies[dep] - log_update( - _("Installing dependency: %s …") - % _dep.get("Description", "n/a") - ) - res = self.dependency_manager.install(config, [dep, _dep]) - if not res.ok: - logging.error( - _("Failed to install dependency: %s") - % _dep.get("Description", "n/a"), - jn=True, - ) - log_update( - _("Failed to install dependency: %s") - % _dep.get("Description", "n/a") - ) - return Result(False) - template_updated = True # save bottle config config.dump(f"{bottle_complete_path}/bottle.yml") diff --git a/bottles/backend/managers/meson.build b/bottles/backend/managers/meson.build index 7fd361cece9..0da12ec2531 100644 --- a/bottles/backend/managers/meson.build +++ b/bottles/backend/managers/meson.build @@ -4,7 +4,6 @@ managersdir = join_paths(pkgdatadir, 'bottles/backend/managers') bottles_sources = [ '__init__.py', 'backup.py', - 'dependency.py', 'library.py', 'manager.py', 'runtime.py', From c48313810d97419d7a2007673fca4b1cd38da291 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Sun, 2 Feb 2025 20:41:37 -0500 Subject: [PATCH 109/146] meta: Remove logger It makes no sense to have the backend configure the logging mechanism. Instead, the frontend should modify the behavior if need be. The backend will just use the `logging` module without configuring anything substantial. --- bottles/backend/cabextract.py | 4 +- bottles/backend/dlls/dll.py | 4 +- bottles/backend/dlls/nvapi.py | 4 +- bottles/backend/downloader.py | 4 +- bottles/backend/health.py | 3 - bottles/backend/logger.py | 113 ------------------ bottles/backend/managers/backup.py | 4 +- bottles/backend/managers/importer.py | 6 +- bottles/backend/managers/library.py | 4 +- bottles/backend/managers/manager.py | 13 +- bottles/backend/managers/steamgriddb.py | 3 - bottles/backend/managers/template.py | 6 +- bottles/backend/managers/thumbnail.py | 4 +- bottles/backend/meson.build | 1 - bottles/backend/repos/repo.py | 4 +- bottles/backend/runner.py | 4 +- bottles/backend/state.py | 4 +- bottles/backend/utils/gpu.py | 4 +- bottles/backend/utils/gsettings_stub.py | 4 +- bottles/backend/utils/manager.py | 4 +- bottles/backend/utils/midi.py | 4 +- bottles/backend/utils/nvidia.py | 4 +- bottles/backend/utils/steam.py | 4 +- bottles/backend/utils/terminal.py | 4 +- bottles/backend/utils/threading.py | 4 +- bottles/backend/wine/cmd.py | 3 - bottles/backend/wine/control.py | 3 - bottles/backend/wine/drives.py | 4 +- bottles/backend/wine/eject.py | 3 - bottles/backend/wine/executor.py | 4 +- bottles/backend/wine/expand.py | 3 - bottles/backend/wine/explorer.py | 3 - bottles/backend/wine/hh.py | 3 - bottles/backend/wine/icinfo.py | 3 - bottles/backend/wine/msiexec.py | 3 - bottles/backend/wine/net.py | 3 - bottles/backend/wine/notepad.py | 3 - bottles/backend/wine/oleview.py | 3 - bottles/backend/wine/progman.py | 3 - bottles/backend/wine/reg.py | 4 +- bottles/backend/wine/regedit.py | 3 - bottles/backend/wine/regkeys.py | 3 - bottles/backend/wine/regsvr32.py | 3 - bottles/backend/wine/rundll32.py | 3 - bottles/backend/wine/start.py | 3 - bottles/backend/wine/taskmgr.py | 3 - bottles/backend/wine/uninstaller.py | 3 - bottles/backend/wine/wineboot.py | 4 +- bottles/backend/wine/winebridge.py | 4 +- bottles/backend/wine/winecfg.py | 4 +- bottles/backend/wine/winecommand.py | 4 +- bottles/backend/wine/winedbg.py | 3 - bottles/backend/wine/winefile.py | 3 - bottles/backend/wine/winepath.py | 3 - bottles/backend/wine/wineprogram.py | 4 +- bottles/backend/wine/wineserver.py | 3 - bottles/backend/wine/winhelp.py | 3 - bottles/backend/wine/xcopy.py | 3 - bottles/frontend/component_entry_row.py | 4 +- bottles/frontend/details_preferences_page.py | 4 +- bottles/frontend/display_dialog.py | 2 - .../frontend/environment_variables_dialog.py | 4 +- bottles/frontend/fsr_dialog.py | 3 - bottles/frontend/launch_options_dialog.py | 4 +- bottles/frontend/library_entry.py | 4 +- bottles/frontend/main.py | 4 +- bottles/frontend/mangohud_dialog.py | 3 - bottles/frontend/vkbasalt_dialog.py | 4 +- bottles/frontend/window.py | 5 +- 69 files changed, 44 insertions(+), 321 deletions(-) delete mode 100644 bottles/backend/logger.py diff --git a/bottles/backend/cabextract.py b/bottles/backend/cabextract.py index bfe6cd00b5a..0e36b4a41f6 100644 --- a/bottles/backend/cabextract.py +++ b/bottles/backend/cabextract.py @@ -20,9 +20,7 @@ import shutil import subprocess -from bottles.backend.logger import Logger - -logging = Logger() +import logging class CabExtract: diff --git a/bottles/backend/dlls/dll.py b/bottles/backend/dlls/dll.py index 954d37b6f68..3bb90bd1cc8 100644 --- a/bottles/backend/dlls/dll.py +++ b/bottles/backend/dlls/dll.py @@ -20,14 +20,12 @@ from abc import abstractmethod from copy import deepcopy -from bottles.backend.logger import Logger +import logging from bottles.backend.models.config import BottleConfig from bottles.backend.models.enum import Arch from bottles.backend.utils.manager import ManagerUtils from bottles.backend.wine.reg import Reg -logging = Logger() - class DLLComponent: base_path: str diff --git a/bottles/backend/dlls/nvapi.py b/bottles/backend/dlls/nvapi.py index b4de3bd719e..013a797384c 100644 --- a/bottles/backend/dlls/nvapi.py +++ b/bottles/backend/dlls/nvapi.py @@ -21,12 +21,10 @@ from bottles.backend.dlls.dll import DLLComponent from bottles.backend.models.config import BottleConfig from bottles.backend.utils.manager import ManagerUtils -from bottles.backend.logger import Logger +import logging from bottles.backend.utils.nvidia import get_nvidia_dll_path -logging = Logger() - class NVAPIComponent(DLLComponent): dlls = { diff --git a/bottles/backend/downloader.py b/bottles/backend/downloader.py index 482e88f0908..d525e7aad32 100644 --- a/bottles/backend/downloader.py +++ b/bottles/backend/downloader.py @@ -21,13 +21,11 @@ import requests -from bottles.backend.logger import Logger +import logging from bottles.backend.models.result import Result from bottles.backend.state import TaskStreamUpdateHandler from bottles.backend.utils.file import FileUtils -logging = Logger() - class Downloader: """ diff --git a/bottles/backend/health.py b/bottles/backend/health.py index 11e87824911..43119b9f1e5 100644 --- a/bottles/backend/health.py +++ b/bottles/backend/health.py @@ -19,15 +19,12 @@ from bottles.backend.utils import yaml import contextlib -from bottles.backend.logger import Logger from bottles.backend.utils.display import DisplayUtils from bottles.backend.utils.gpu import GPUUtils from bottles.backend.utils.generic import is_glibc_min_available from bottles.backend.utils.file import FileUtils from bottles.backend.params import APP_VERSION -logging = Logger() - class HealthChecker: x11: bool = False diff --git a/bottles/backend/logger.py b/bottles/backend/logger.py deleted file mode 100644 index 05bba87f5c0..00000000000 --- a/bottles/backend/logger.py +++ /dev/null @@ -1,113 +0,0 @@ -# logger.py -# -# Copyright 2022 brombinmirko -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, in version 3 of the License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -import logging -import os -import re - -from bottles.backend.globals import Paths -from bottles.backend.managers.journal import JournalManager, JournalSeverity - -# Set default logging level -logging.basicConfig(level=logging.DEBUG) - - -class Logger(logging.getLoggerClass()): - """ - This class is a wrapper for the logging module. It provides - custom formats for the log messages. - """ - - __color_map = {"debug": 37, "info": 36, "warning": 33, "error": 31, "critical": 41} - __format_log = { - "fmt": "\033[80m%(asctime)s \033[1m(%(levelname)s)\033[0m %(message)s \033[0m", - "datefmt": "%H:%M:%S", - } - - def __color(self, level, message: str): - if message and "\n" in message: - message = message.replace("\n", "\n\t") + "\n" - color_id = self.__color_map[level] - return "\033[%dm%s\033[0m" % (color_id, message) - - def __init__(self, formatter=None): - if formatter is None: - formatter = self.__format_log - formatter = logging.Formatter(**formatter) - - self.root.setLevel(os.environ.get("LOG_LEVEL") or logging.INFO) - self.root.handlers = [] - - handler = logging.StreamHandler() - handler.setFormatter(formatter) - self.root.addHandler(handler) - - def debug(self, message, **kwargs): - self.root.debug( - self.__color("debug", message), - ) - - def info(self, message, jn=False, **kwargs): - self.root.info( - self.__color("info", message), - ) - if jn: - JournalManager.write(JournalSeverity.INFO, message) - - def warning(self, message, jn=True, **kwargs): - self.root.warning( - self.__color("warning", message), - ) - if jn: - JournalManager.write(JournalSeverity.WARNING, message) - - def error(self, message, jn=True, **kwargs): - self.root.error( - self.__color("error", message), - ) - if jn: - JournalManager.write(JournalSeverity.ERROR, message) - - def critical(self, message, jn=True, **kwargs): - self.root.critical( - self.__color("critical", message), - ) - if jn: - JournalManager.write(JournalSeverity.CRITICAL, message) - - @staticmethod - def write_log(data: list): - """ - Writes a crash.log file. It finds and replace the user's home directory - with "USER" as a proposed standard for crash reports. - """ - log_path = f"{Paths.xdg_data_home}/bottles/crash.log" - - with open(log_path, "w") as crash_log: - for d in data: - # replace username with "USER" as standard - if "/home/" in d: - d = re.sub(r"/home/([^/]*)/", r"/home/USER/", d) - - crash_log.write(d) - - # we write the same to the journal for convenience - JournalManager.write( - severity=JournalSeverity.CRASH, message="A crash has been detected." - ) - - def set_silent(self): - self.root.handlers = [] diff --git a/bottles/backend/managers/backup.py b/bottles/backend/managers/backup.py index 7a60311521a..59223a9dee5 100644 --- a/bottles/backend/managers/backup.py +++ b/bottles/backend/managers/backup.py @@ -22,7 +22,7 @@ from gettext import gettext as _ from bottles.backend.globals import Paths -from bottles.backend.logger import Logger +import logging from bottles.backend.managers.manager import Manager from bottles.backend.models.config import BottleConfig from bottles.backend.models.result import Result @@ -30,8 +30,6 @@ from bottles.backend.utils import yaml from bottles.backend.utils.manager import ManagerUtils -logging = Logger() - class BackupManager: @staticmethod diff --git a/bottles/backend/managers/importer.py b/bottles/backend/managers/importer.py index 8d3b14cf8ed..14f4c4e30c0 100644 --- a/bottles/backend/managers/importer.py +++ b/bottles/backend/managers/importer.py @@ -22,12 +22,10 @@ from glob import glob from datetime import datetime -from bottles.backend.logger import Logger +import logging from bottles.backend.globals import TrdyPaths, Paths from bottles.backend.models.result import Result -logging = Logger() - class ImportManager: def __init__(self, manager): @@ -125,5 +123,5 @@ def import_wineprefix(self, wineprefix: dict) -> Result: # update bottles view self.manager.update_bottles(silent=True) - logging.info(f"Wine prefix {wineprefix['Name']} imported as bottle.", jn=True) + logging.info(f"Wine prefix {wineprefix['Name']} imported as bottle.") return Result(True) diff --git a/bottles/backend/managers/library.py b/bottles/backend/managers/library.py index d462c8de511..2b83c00f16e 100644 --- a/bottles/backend/managers/library.py +++ b/bottles/backend/managers/library.py @@ -21,12 +21,10 @@ from bottles.backend.models.config import BottleConfig from bottles.backend.utils import yaml -from bottles.backend.logger import Logger +import logging from bottles.backend.globals import Paths from bottles.backend.managers.steamgriddb import SteamGridDBManager -logging = Logger() - class LibraryManager: """ diff --git a/bottles/backend/managers/manager.py b/bottles/backend/managers/manager.py index 7ac90047bad..053cfac9067 100644 --- a/bottles/backend/managers/manager.py +++ b/bottles/backend/managers/manager.py @@ -35,7 +35,7 @@ from bottles.backend.dlls.nvapi import NVAPIComponent from bottles.backend.dlls.vkd3d import VKD3DComponent from bottles.backend.globals import Paths -from bottles.backend.logger import Logger +import logging from bottles.backend.managers.epicgamesstore import EpicGamesStoreManager from bottles.backend.managers.importer import ImportManager from bottles.backend.managers.library import LibraryManager @@ -63,8 +63,6 @@ from bottles.backend.wine.winepath import WinePath from bottles.backend.wine.wineserver import WineServer -logging = Logger() - class Manager(metaclass=Singleton): """ @@ -912,7 +910,7 @@ def components_check(): nonlocal check_attempts if check_attempts > 2: - logging.error("Fail to install components, tried 3 times.", jn=True) + logging.error("Fail to install components, tried 3 times.") log_update(_("Fail to install components, tried 3 times.")) return False @@ -1005,9 +1003,7 @@ def components_check(): os.makedirs(bottle_drive_c) FileUtils.chattr_f(bottle_drive_c) except: - logging.error( - f"Failed to create bottle directory: {bottle_complete_path}", jn=True - ) + logging.error(f"Failed to create bottle directory: {bottle_complete_path}") log_update(_("Failed to create bottle directory.")) return Result(False) @@ -1021,7 +1017,6 @@ def components_check(): except: logging.error( f"Failed to create placeholder directory/file at: {placeholder_dir}", - jn=True, ) log_update(_("Failed to create placeholder directory/file.")) return Result(False) @@ -1206,7 +1201,7 @@ def components_check(): config.dump(f"{bottle_complete_path}/bottle.yml") # set status created and UI usability - logging.info(f"New bottle created: {bottle_name}", jn=True) + logging.info(f"New bottle created: {bottle_name}") log_update(_("Finalizing…")) # wait for all registry changes to be applied diff --git a/bottles/backend/managers/steamgriddb.py b/bottles/backend/managers/steamgriddb.py index 7670f7b85ef..f87277c9959 100644 --- a/bottles/backend/managers/steamgriddb.py +++ b/bottles/backend/managers/steamgriddb.py @@ -19,12 +19,9 @@ import uuid import requests -from bottles.backend.logger import Logger from bottles.backend.models.config import BottleConfig from bottles.backend.utils.manager import ManagerUtils -logging = Logger() - class SteamGridDBManager: @staticmethod diff --git a/bottles/backend/managers/template.py b/bottles/backend/managers/template.py index 04bb82355fd..0cde2eb135e 100644 --- a/bottles/backend/managers/template.py +++ b/bottles/backend/managers/template.py @@ -25,13 +25,11 @@ from datetime import datetime from pathlib import Path -from bottles.backend.logger import Logger +import logging from bottles.backend.utils.manager import ManagerUtils from bottles.backend.globals import Paths from bottles.backend.models.samples import Samples -logging = Logger() - class TemplateManager: @staticmethod @@ -73,7 +71,7 @@ def new(env: str, config: BottleConfig): with open(os.path.join(_path, "template.yml"), "w") as f: yaml.dump(template, f) - logging.info(f"New template {env} created", jn=True) + logging.info(f"New template {env} created") if not TemplateManager.__validate_template(_uuid): logging.error("Template validation failed, will retry with next bottle.") diff --git a/bottles/backend/managers/thumbnail.py b/bottles/backend/managers/thumbnail.py index ea6183059a6..b63d750d1e4 100644 --- a/bottles/backend/managers/thumbnail.py +++ b/bottles/backend/managers/thumbnail.py @@ -17,12 +17,10 @@ import os -from bottles.backend.logger import Logger +import logging from bottles.backend.models.config import BottleConfig from bottles.backend.utils.manager import ManagerUtils -logging = Logger() - class ThumbnailManager: @staticmethod diff --git a/bottles/backend/meson.build b/bottles/backend/meson.build index e3ef11e826f..5bc3697a351 100644 --- a/bottles/backend/meson.build +++ b/bottles/backend/meson.build @@ -21,7 +21,6 @@ bottles_sources = [ 'diff.py', 'health.py', 'downloader.py', - 'logger.py', 'cabextract.py', 'state.py', params_file diff --git a/bottles/backend/repos/repo.py b/bottles/backend/repos/repo.py index 3601cc82a2b..657a10020ad 100644 --- a/bottles/backend/repos/repo.py +++ b/bottles/backend/repos/repo.py @@ -19,13 +19,11 @@ import pycurl -from bottles.backend.logger import Logger +import logging from bottles.backend.state import EventManager, Events from bottles.backend.utils import yaml from bottles.backend.utils.threading import RunAsync -logging = Logger() - class Repo: name: str = "" diff --git a/bottles/backend/runner.py b/bottles/backend/runner.py index 270916674a8..f37a7e03002 100644 --- a/bottles/backend/runner.py +++ b/bottles/backend/runner.py @@ -18,7 +18,7 @@ import os from typing import TYPE_CHECKING -from bottles.backend.logger import Logger +import logging from bottles.backend.managers.runtime import RuntimeManager from bottles.backend.models.config import BottleConfig from bottles.backend.models.result import Result @@ -29,8 +29,6 @@ if TYPE_CHECKING: from bottles.backend.managers.manager import Manager -logging = Logger() - class Runner: """ diff --git a/bottles/backend/state.py b/bottles/backend/state.py index 07b2d02a1f7..9beee1433df 100644 --- a/bottles/backend/state.py +++ b/bottles/backend/state.py @@ -6,11 +6,9 @@ from collections.abc import Callable from uuid import UUID, uuid4 -from bottles.backend.logger import Logger +import logging from bottles.backend.models.result import Result -logging = Logger() - class Locks(Enum): ComponentsInstall = "components.install" diff --git a/bottles/backend/utils/gpu.py b/bottles/backend/utils/gpu.py index 00207971d92..8b930e971a5 100644 --- a/bottles/backend/utils/gpu.py +++ b/bottles/backend/utils/gpu.py @@ -22,9 +22,7 @@ from bottles.backend.utils.nvidia import get_nvidia_dll_path from bottles.backend.utils.vulkan import VulkanUtils -from bottles.backend.logger import Logger - -logging = Logger() +import logging class GPUVendors(Enum): diff --git a/bottles/backend/utils/gsettings_stub.py b/bottles/backend/utils/gsettings_stub.py index d150c49276e..08d8df105a7 100644 --- a/bottles/backend/utils/gsettings_stub.py +++ b/bottles/backend/utils/gsettings_stub.py @@ -1,6 +1,4 @@ -from bottles.backend.logger import Logger - -logging = Logger() +import logging class GSettingsStub: diff --git a/bottles/backend/utils/manager.py b/bottles/backend/utils/manager.py index 1a7e29d0ed8..55e0791ff1b 100644 --- a/bottles/backend/utils/manager.py +++ b/bottles/backend/utils/manager.py @@ -24,15 +24,13 @@ import icoextract # type: ignore [import-untyped] from bottles.backend.globals import Paths -from bottles.backend.logger import Logger +import logging from bottles.backend.models.config import BottleConfig from bottles.backend.models.result import Result from bottles.backend.state import SignalManager, Signals from bottles.backend.utils.generic import get_mime from bottles.backend.utils.imagemagick import ImageMagickUtils -logging = Logger() - class ManagerUtils: """ diff --git a/bottles/backend/utils/midi.py b/bottles/backend/utils/midi.py index a8bce4e8347..d80cfb4e4fe 100644 --- a/bottles/backend/utils/midi.py +++ b/bottles/backend/utils/midi.py @@ -19,12 +19,10 @@ from ctypes import c_void_p from fluidsynth import cfunc, Synth # type: ignore [import-untyped] -from bottles.backend.logger import Logger +import logging from bottles.backend.models.config import BottleConfig from bottles.backend.wine.reg import Reg -logging = Logger() - class FluidSynth: """FluidSynth instance bounded to a unique SoundFont (.sf2, .sf3) file.""" diff --git a/bottles/backend/utils/nvidia.py b/bottles/backend/utils/nvidia.py index ea49e588f7d..46d3d41fcb3 100644 --- a/bottles/backend/utils/nvidia.py +++ b/bottles/backend/utils/nvidia.py @@ -5,9 +5,9 @@ import os from ctypes import CDLL, POINTER, Structure, addressof, c_char_p, c_int, c_void_p, cast -from bottles.backend.logger import Logger +import logging + -logging = Logger() RTLD_DI_LINKMAP = 2 diff --git a/bottles/backend/utils/steam.py b/bottles/backend/utils/steam.py index d420d2c2125..5fcf9d9b97f 100644 --- a/bottles/backend/utils/steam.py +++ b/bottles/backend/utils/steam.py @@ -19,12 +19,10 @@ import shlex from typing import TextIO -from bottles.backend.logger import Logger +import logging from bottles.backend.models.vdict import VDFDict from bottles.backend.utils import vdf -logging = Logger() - class SteamUtils: @staticmethod diff --git a/bottles/backend/utils/terminal.py b/bottles/backend/utils/terminal.py index 32513bb71fb..66c0c93ee94 100644 --- a/bottles/backend/utils/terminal.py +++ b/bottles/backend/utils/terminal.py @@ -19,9 +19,7 @@ import subprocess import shlex -from bottles.backend.logger import Logger - -logging = Logger() +import logging class TerminalUtils: diff --git a/bottles/backend/utils/threading.py b/bottles/backend/utils/threading.py index 911dc0fb3a1..f0f137f8ade 100644 --- a/bottles/backend/utils/threading.py +++ b/bottles/backend/utils/threading.py @@ -21,9 +21,7 @@ import traceback from typing import Any -from bottles.backend.logger import Logger - -logging = Logger() +import logging class RunAsync(threading.Thread): diff --git a/bottles/backend/wine/cmd.py b/bottles/backend/wine/cmd.py index 268e152a454..42f751bc6ce 100644 --- a/bottles/backend/wine/cmd.py +++ b/bottles/backend/wine/cmd.py @@ -1,8 +1,5 @@ -from bottles.backend.logger import Logger from bottles.backend.wine.wineprogram import WineProgram -logging = Logger() - class CMD(WineProgram): program = "Wine Command Line" diff --git a/bottles/backend/wine/control.py b/bottles/backend/wine/control.py index c9b2800f5a9..f40657c2f06 100644 --- a/bottles/backend/wine/control.py +++ b/bottles/backend/wine/control.py @@ -1,8 +1,5 @@ -from bottles.backend.logger import Logger from bottles.backend.wine.wineprogram import WineProgram -logging = Logger() - class Control(WineProgram): program = "Wine Control Panel" diff --git a/bottles/backend/wine/drives.py b/bottles/backend/wine/drives.py index a87b3dc9400..0702414bd21 100644 --- a/bottles/backend/wine/drives.py +++ b/bottles/backend/wine/drives.py @@ -1,11 +1,9 @@ import os -from bottles.backend.logger import Logger +import logging from bottles.backend.models.config import BottleConfig from bottles.backend.utils.manager import ManagerUtils -logging = Logger() - class Drives: def __init__(self, config: BottleConfig): diff --git a/bottles/backend/wine/eject.py b/bottles/backend/wine/eject.py index 703c047a1da..e4621f8a6ba 100644 --- a/bottles/backend/wine/eject.py +++ b/bottles/backend/wine/eject.py @@ -1,8 +1,5 @@ -from bottles.backend.logger import Logger from bottles.backend.wine.wineprogram import WineProgram -logging = Logger() - class Eject(WineProgram): program = "Wine Eject CLI" diff --git a/bottles/backend/wine/executor.py b/bottles/backend/wine/executor.py index f3eaee0d6b2..d9554e27f1b 100644 --- a/bottles/backend/wine/executor.py +++ b/bottles/backend/wine/executor.py @@ -5,7 +5,7 @@ from bottles.backend.dlls.dxvk import DXVKComponent from bottles.backend.dlls.nvapi import NVAPIComponent from bottles.backend.dlls.vkd3d import VKD3DComponent -from bottles.backend.logger import Logger +import logging from bottles.backend.models.config import BottleConfig from bottles.backend.models.result import Result from bottles.backend.utils.manager import ManagerUtils @@ -18,8 +18,6 @@ from bottles.backend.wine.winedbg import WineDbg from bottles.backend.wine.winepath import WinePath -logging = Logger() - class WineExecutor: def __init__( diff --git a/bottles/backend/wine/expand.py b/bottles/backend/wine/expand.py index 7832169c12f..a2a233b3b32 100644 --- a/bottles/backend/wine/expand.py +++ b/bottles/backend/wine/expand.py @@ -1,8 +1,5 @@ -from bottles.backend.logger import Logger from bottles.backend.wine.wineprogram import WineProgram -logging = Logger() - class Expand(WineProgram): program = "Wine cabinet expander" diff --git a/bottles/backend/wine/explorer.py b/bottles/backend/wine/explorer.py index d6588cda075..259a13a8c08 100644 --- a/bottles/backend/wine/explorer.py +++ b/bottles/backend/wine/explorer.py @@ -1,8 +1,5 @@ -from bottles.backend.logger import Logger from bottles.backend.wine.wineprogram import WineProgram -logging = Logger() - class Explorer(WineProgram): program = "Wine Explorer" diff --git a/bottles/backend/wine/hh.py b/bottles/backend/wine/hh.py index d294be0d731..bc26d7bdfa1 100644 --- a/bottles/backend/wine/hh.py +++ b/bottles/backend/wine/hh.py @@ -1,8 +1,5 @@ -from bottles.backend.logger import Logger from bottles.backend.wine.wineprogram import WineProgram -logging = Logger() - class Hh(WineProgram): program = "Wine HTML help viewer" diff --git a/bottles/backend/wine/icinfo.py b/bottles/backend/wine/icinfo.py index 9cc1fd3a813..2a34356022e 100644 --- a/bottles/backend/wine/icinfo.py +++ b/bottles/backend/wine/icinfo.py @@ -1,8 +1,5 @@ -from bottles.backend.logger import Logger from bottles.backend.wine.wineprogram import WineProgram -logging = Logger() - class Icinfo(WineProgram): program = "List installed video compressors" diff --git a/bottles/backend/wine/msiexec.py b/bottles/backend/wine/msiexec.py index 340d4f5aabb..cfbac308062 100644 --- a/bottles/backend/wine/msiexec.py +++ b/bottles/backend/wine/msiexec.py @@ -1,8 +1,5 @@ -from bottles.backend.logger import Logger from bottles.backend.wine.wineprogram import WineProgram -logging = Logger() - class MsiExec(WineProgram): program = "Wine MSI Installer" diff --git a/bottles/backend/wine/net.py b/bottles/backend/wine/net.py index 41da0793b2f..aaa352396bd 100644 --- a/bottles/backend/wine/net.py +++ b/bottles/backend/wine/net.py @@ -1,8 +1,5 @@ -from bottles.backend.logger import Logger from bottles.backend.wine.wineprogram import WineProgram -logging = Logger() - class Net(WineProgram): program = "Wine Services manager" diff --git a/bottles/backend/wine/notepad.py b/bottles/backend/wine/notepad.py index c2e361d7148..5651e364ea6 100644 --- a/bottles/backend/wine/notepad.py +++ b/bottles/backend/wine/notepad.py @@ -1,8 +1,5 @@ -from bottles.backend.logger import Logger from bottles.backend.wine.wineprogram import WineProgram -logging = Logger() - class Notepad(WineProgram): program = "Wine Notepad" diff --git a/bottles/backend/wine/oleview.py b/bottles/backend/wine/oleview.py index 93da9a76b55..f0cb1c6144e 100644 --- a/bottles/backend/wine/oleview.py +++ b/bottles/backend/wine/oleview.py @@ -1,8 +1,5 @@ -from bottles.backend.logger import Logger from bottles.backend.wine.wineprogram import WineProgram -logging = Logger() - class Oleview(WineProgram): program = "OLE/COM object viewer" diff --git a/bottles/backend/wine/progman.py b/bottles/backend/wine/progman.py index 8996a0e3016..bb1eaaeb114 100644 --- a/bottles/backend/wine/progman.py +++ b/bottles/backend/wine/progman.py @@ -1,8 +1,5 @@ -from bottles.backend.logger import Logger from bottles.backend.wine.wineprogram import WineProgram -logging = Logger() - class Progman(WineProgram): program = "Wine Program Manager" diff --git a/bottles/backend/wine/reg.py b/bottles/backend/wine/reg.py index 83c78a1e162..dfbc27e0bd3 100644 --- a/bottles/backend/wine/reg.py +++ b/bottles/backend/wine/reg.py @@ -6,14 +6,12 @@ from itertools import groupby from bottles.backend.globals import Paths -from bottles.backend.logger import Logger +import logging from bottles.backend.utils.generic import random_string from bottles.backend.utils.manager import ManagerUtils from bottles.backend.wine.winedbg import WineDbg from bottles.backend.wine.wineprogram import WineProgram -logging = Logger() - @dataclasses.dataclass class RegItem: diff --git a/bottles/backend/wine/regedit.py b/bottles/backend/wine/regedit.py index 25ffa665339..fb0d16857ed 100644 --- a/bottles/backend/wine/regedit.py +++ b/bottles/backend/wine/regedit.py @@ -1,8 +1,5 @@ -from bottles.backend.logger import Logger from bottles.backend.wine.wineprogram import WineProgram -logging = Logger() - class Regedit(WineProgram): program = "Wine Registry Editor" diff --git a/bottles/backend/wine/regkeys.py b/bottles/backend/wine/regkeys.py index 63f0883e533..343e724ebb7 100644 --- a/bottles/backend/wine/regkeys.py +++ b/bottles/backend/wine/regkeys.py @@ -1,4 +1,3 @@ -from bottles.backend.logger import Logger from bottles.backend.models.config import BottleConfig from bottles.backend.models.enum import Arch from bottles.backend.wine.catalogs import win_versions @@ -6,8 +5,6 @@ from bottles.backend.wine.wineboot import WineBoot from bottles.backend.wine.winecfg import WineCfg -logging = Logger() - class RegKeys: def __init__(self, config: BottleConfig): diff --git a/bottles/backend/wine/regsvr32.py b/bottles/backend/wine/regsvr32.py index 420c829865d..02f4d5a45fd 100644 --- a/bottles/backend/wine/regsvr32.py +++ b/bottles/backend/wine/regsvr32.py @@ -1,8 +1,5 @@ -from bottles.backend.logger import Logger from bottles.backend.wine.wineprogram import WineProgram -logging = Logger() - class Regsvr32(WineProgram): program = "Wine DLL Registration Server" diff --git a/bottles/backend/wine/rundll32.py b/bottles/backend/wine/rundll32.py index c4ed2f9de3e..f5308d6bb54 100644 --- a/bottles/backend/wine/rundll32.py +++ b/bottles/backend/wine/rundll32.py @@ -1,8 +1,5 @@ -from bottles.backend.logger import Logger from bottles.backend.wine.wineprogram import WineProgram -logging = Logger() - class RunDLL32(WineProgram): program = "32-bit DLLs loader and runner" diff --git a/bottles/backend/wine/start.py b/bottles/backend/wine/start.py index d144dae66a4..e491a93db25 100644 --- a/bottles/backend/wine/start.py +++ b/bottles/backend/wine/start.py @@ -1,9 +1,6 @@ -from bottles.backend.logger import Logger from bottles.backend.wine.wineprogram import WineProgram from bottles.backend.wine.winepath import WinePath -logging = Logger() - class Start(WineProgram): program = "Wine Starter" diff --git a/bottles/backend/wine/taskmgr.py b/bottles/backend/wine/taskmgr.py index 7f27f415f76..0216fe32ce7 100644 --- a/bottles/backend/wine/taskmgr.py +++ b/bottles/backend/wine/taskmgr.py @@ -1,8 +1,5 @@ -from bottles.backend.logger import Logger from bottles.backend.wine.wineprogram import WineProgram -logging = Logger() - class Taskmgr(WineProgram): program = "Wine Task Manager" diff --git a/bottles/backend/wine/uninstaller.py b/bottles/backend/wine/uninstaller.py index 511db791bdc..f6c824224fa 100644 --- a/bottles/backend/wine/uninstaller.py +++ b/bottles/backend/wine/uninstaller.py @@ -1,8 +1,5 @@ -from bottles.backend.logger import Logger from bottles.backend.wine.wineprogram import WineProgram -logging = Logger() - class Uninstaller(WineProgram): program = "Wine Uninstaller" diff --git a/bottles/backend/wine/wineboot.py b/bottles/backend/wine/wineboot.py index b489f321f79..e7905228ae8 100644 --- a/bottles/backend/wine/wineboot.py +++ b/bottles/backend/wine/wineboot.py @@ -1,12 +1,10 @@ -from bottles.backend.logger import Logger +import logging from bottles.backend.wine.wineprogram import WineProgram from bottles.backend.wine.wineserver import WineServer import os import signal -logging = Logger() - class WineBoot(WineProgram): program = "Wine Runtime tool" diff --git a/bottles/backend/wine/winebridge.py b/bottles/backend/wine/winebridge.py index 8bd1351c4d3..31988ac4b3f 100644 --- a/bottles/backend/wine/winebridge.py +++ b/bottles/backend/wine/winebridge.py @@ -1,11 +1,9 @@ import os -from bottles.backend.logger import Logger +import logging from bottles.backend.wine.wineprogram import WineProgram from bottles.backend.wine.wineserver import WineServer -logging = Logger() - class WineBridge(WineProgram): program = "Wine Bridge" diff --git a/bottles/backend/wine/winecfg.py b/bottles/backend/wine/winecfg.py index 67b28456556..f5041a782ff 100644 --- a/bottles/backend/wine/winecfg.py +++ b/bottles/backend/wine/winecfg.py @@ -1,12 +1,10 @@ import os -from bottles.backend.logger import Logger +import logging from bottles.backend.wine.wineprogram import WineProgram from bottles.backend.wine.winedbg import WineDbg from bottles.backend.wine.wineboot import WineBoot -logging = Logger() - class WineCfg(WineProgram): program = "Wine Configuration" diff --git a/bottles/backend/wine/winecommand.py b/bottles/backend/wine/winecommand.py index 122f3cdd88d..30fb1799c06 100644 --- a/bottles/backend/wine/winecommand.py +++ b/bottles/backend/wine/winecommand.py @@ -13,7 +13,7 @@ obs_vkc_available, vmtouch_available, ) -from bottles.backend.logger import Logger +import logging from bottles.backend.managers.runtime import RuntimeManager from bottles.backend.managers.sandbox import SandboxManager from bottles.backend.models.config import BottleConfig @@ -25,8 +25,6 @@ from bottles.backend.utils.terminal import TerminalUtils from bottles.backend.utils.steam import SteamUtils -logging = Logger() - class WineEnv: """ diff --git a/bottles/backend/wine/winedbg.py b/bottles/backend/wine/winedbg.py index 738d1137c33..4d99e5131bf 100644 --- a/bottles/backend/wine/winedbg.py +++ b/bottles/backend/wine/winedbg.py @@ -2,14 +2,11 @@ import time import subprocess -from bottles.backend.logger import Logger from bottles.backend.wine.wineprogram import WineProgram from bottles.backend.wine.wineserver import WineServer from bottles.backend.wine.wineboot import WineBoot from bottles.backend.utils.decorators import cache -logging = Logger() - class WineDbg(WineProgram): program = "Wine debug tool" diff --git a/bottles/backend/wine/winefile.py b/bottles/backend/wine/winefile.py index 28152f8e1ac..ddd8030ef2c 100644 --- a/bottles/backend/wine/winefile.py +++ b/bottles/backend/wine/winefile.py @@ -1,8 +1,5 @@ -from bottles.backend.logger import Logger from bottles.backend.wine.wineprogram import WineProgram -logging = Logger() - class WineFile(WineProgram): program = "Wine File Explorer" diff --git a/bottles/backend/wine/winepath.py b/bottles/backend/wine/winepath.py index aaff7ba266b..36b81e1b153 100644 --- a/bottles/backend/wine/winepath.py +++ b/bottles/backend/wine/winepath.py @@ -1,12 +1,9 @@ import re from functools import lru_cache -from bottles.backend.logger import Logger from bottles.backend.wine.wineprogram import WineProgram from bottles.backend.utils.manager import ManagerUtils -logging = Logger() - class WinePath(WineProgram): program = "Wine path converter" diff --git a/bottles/backend/wine/wineprogram.py b/bottles/backend/wine/wineprogram.py index 32dd650343b..570f0dd647f 100644 --- a/bottles/backend/wine/wineprogram.py +++ b/bottles/backend/wine/wineprogram.py @@ -1,12 +1,10 @@ import os -from bottles.backend.logger import Logger +import logging from bottles.backend.globals import Paths from bottles.backend.models.config import BottleConfig from bottles.backend.wine.winecommand import WineCommand -logging = Logger() - class WineProgram: program: str = "unknown" diff --git a/bottles/backend/wine/wineserver.py b/bottles/backend/wine/wineserver.py index 60709b1279c..37bb8a96ba4 100644 --- a/bottles/backend/wine/wineserver.py +++ b/bottles/backend/wine/wineserver.py @@ -2,14 +2,11 @@ import subprocess import time -from bottles.backend.logger import Logger from bottles.backend.utils.manager import ManagerUtils from bottles.backend.utils.proc import ProcUtils from bottles.backend.utils.steam import SteamUtils from bottles.backend.wine.wineprogram import WineProgram -logging = Logger() - class WineServer(WineProgram): program = "Wine Server" diff --git a/bottles/backend/wine/winhelp.py b/bottles/backend/wine/winhelp.py index b09e940fa24..d84ec10583d 100644 --- a/bottles/backend/wine/winhelp.py +++ b/bottles/backend/wine/winhelp.py @@ -1,8 +1,5 @@ -from bottles.backend.logger import Logger from bottles.backend.wine.wineprogram import WineProgram -logging = Logger() - class WinHelp(WineProgram): program = "Microsoft help file viewer" diff --git a/bottles/backend/wine/xcopy.py b/bottles/backend/wine/xcopy.py index ba8e8c97daa..b7cfe446563 100644 --- a/bottles/backend/wine/xcopy.py +++ b/bottles/backend/wine/xcopy.py @@ -1,10 +1,7 @@ from datetime import datetime -from bottles.backend.logger import Logger from bottles.backend.wine.wineprogram import WineProgram -logging = Logger() - class Xcopy(WineProgram): program = "Wine Xcopy implementation" diff --git a/bottles/frontend/component_entry_row.py b/bottles/frontend/component_entry_row.py index f8ae055f2e8..569d2f1f73c 100644 --- a/bottles/frontend/component_entry_row.py +++ b/bottles/frontend/component_entry_row.py @@ -19,14 +19,12 @@ from gi.repository import Gtk, GObject, Adw -from bottles.backend.logger import Logger +import logging from bottles.backend.state import Status from bottles.backend.utils.manager import ManagerUtils from bottles.backend.utils.threading import RunAsync from bottles.frontend.gtk import GtkUtils -logging = Logger() - @Gtk.Template(resource_path="/com/usebottles/bottles/component-entry-row.ui") class ComponentEntryRow(Adw.ActionRow): diff --git a/bottles/frontend/details_preferences_page.py b/bottles/frontend/details_preferences_page.py index 8d96591a00a..e6178ea436e 100644 --- a/bottles/frontend/details_preferences_page.py +++ b/bottles/frontend/details_preferences_page.py @@ -31,7 +31,7 @@ gamescope_available, base_version, ) -from bottles.backend.logger import Logger +import logging from bottles.backend.managers.library import LibraryManager from bottles.backend.managers.runtime import RuntimeManager from bottles.backend.models.config import BottleConfig @@ -57,8 +57,6 @@ from bottles.frontend.vkbasalt_dialog import VkBasaltDialog from bottles.frontend.vmtouch_dialog import VmtouchDialog -logging = Logger() - # noinspection PyUnusedLocal @Gtk.Template(resource_path="/com/usebottles/bottles/details-preferences-page.ui") diff --git a/bottles/frontend/display_dialog.py b/bottles/frontend/display_dialog.py index d5a605a3941..9df9dd5c00f 100644 --- a/bottles/frontend/display_dialog.py +++ b/bottles/frontend/display_dialog.py @@ -19,13 +19,11 @@ from gi.repository import Gtk, GLib, Adw -from bottles.backend.logger import Logger from bottles.backend.utils.threading import RunAsync from bottles.backend.wine.reg import Reg from bottles.backend.wine.regkeys import RegKeys from bottles.frontend.gtk import GtkUtils -logging = Logger() renderers = ["gl", "gdi", "vulkan"] diff --git a/bottles/frontend/environment_variables_dialog.py b/bottles/frontend/environment_variables_dialog.py index 8252a135f0a..0a8b1b8ed81 100644 --- a/bottles/frontend/environment_variables_dialog.py +++ b/bottles/frontend/environment_variables_dialog.py @@ -19,12 +19,10 @@ from gi.repository import Gtk, GLib, Adw -from bottles.backend.logger import Logger +import logging from bottles.frontend.gtk import GtkUtils from bottles.frontend.sh import ShUtils -logging = Logger() - @Gtk.Template(resource_path="/com/usebottles/bottles/env-var-entry.ui") class EnvironmentVariableEntryRow(Adw.EntryRow): diff --git a/bottles/frontend/fsr_dialog.py b/bottles/frontend/fsr_dialog.py index e35d83d1bf1..8a08df0acba 100644 --- a/bottles/frontend/fsr_dialog.py +++ b/bottles/frontend/fsr_dialog.py @@ -18,9 +18,6 @@ from gettext import gettext as _ from gi.repository import Gtk, GLib, Adw -from bottles.backend.logger import Logger - -logging = Logger() @Gtk.Template(resource_path="/com/usebottles/bottles/fsr-dialog.ui") diff --git a/bottles/frontend/launch_options_dialog.py b/bottles/frontend/launch_options_dialog.py index 97c4dc9b25b..0cba23b813f 100644 --- a/bottles/frontend/launch_options_dialog.py +++ b/bottles/frontend/launch_options_dialog.py @@ -18,12 +18,10 @@ from gi.repository import Gtk, GLib, GObject, Adw from bottles.backend.utils.manager import ManagerUtils -from bottles.backend.logger import Logger +import logging from bottles.frontend.filters import add_all_filters, add_soundfont_filters from gettext import gettext as _ -logging = Logger() - @Gtk.Template(resource_path="/com/usebottles/bottles/launch-options-dialog.ui") class LaunchOptionsDialog(Adw.Window): diff --git a/bottles/frontend/library_entry.py b/bottles/frontend/library_entry.py index 6c9b52c2284..447ec7b11a1 100644 --- a/bottles/frontend/library_entry.py +++ b/bottles/frontend/library_entry.py @@ -19,7 +19,7 @@ from gi.repository import Gtk, Gdk -from bottles.backend.logger import Logger +import logging from bottles.backend.managers.library import LibraryManager from bottles.backend.managers.thumbnail import ThumbnailManager from bottles.backend.models.result import Result @@ -28,8 +28,6 @@ from bottles.backend.wine.winedbg import WineDbg from bottles.frontend.gtk import GtkUtils -logging = Logger() - @Gtk.Template(resource_path="/com/usebottles/bottles/library-entry.ui") class LibraryEntry(Gtk.Box): diff --git a/bottles/frontend/main.py b/bottles/frontend/main.py index 54e5cb26d98..19796683295 100644 --- a/bottles/frontend/main.py +++ b/bottles/frontend/main.py @@ -22,7 +22,7 @@ import webbrowser from os import path -from bottles.backend.logger import Logger +import logging from bottles.backend.health import HealthChecker from bottles.frontend.params import ( APP_ID, @@ -43,8 +43,6 @@ from bottles.frontend.preferences import PreferencesWindow -logging = Logger() - # region Translations """ This code snippet searches for and uploads translations to different diff --git a/bottles/frontend/mangohud_dialog.py b/bottles/frontend/mangohud_dialog.py index 7690c2ac539..4f35dfaa263 100644 --- a/bottles/frontend/mangohud_dialog.py +++ b/bottles/frontend/mangohud_dialog.py @@ -16,9 +16,6 @@ # along with this program. If not, see . from gi.repository import Gtk, GLib, Adw -from bottles.backend.logger import Logger - -logging = Logger() @Gtk.Template(resource_path="/com/usebottles/bottles/mangohud-dialog.ui") diff --git a/bottles/frontend/vkbasalt_dialog.py b/bottles/frontend/vkbasalt_dialog.py index f3f77c66454..c79c5112c00 100644 --- a/bottles/frontend/vkbasalt_dialog.py +++ b/bottles/frontend/vkbasalt_dialog.py @@ -29,9 +29,7 @@ from gi.repository import Gtk, GLib, Adw from vkbasalt.lib import parse, ParseConfig # type: ignore [import-untyped] from bottles.backend.utils.manager import ManagerUtils -from bottles.backend.logger import Logger - -logging = Logger() +import logging class VkBasaltSettings: diff --git a/bottles/frontend/window.py b/bottles/frontend/window.py index f6e8a344c34..6156bc122b2 100644 --- a/bottles/frontend/window.py +++ b/bottles/frontend/window.py @@ -24,7 +24,7 @@ from bottles.backend.globals import Paths from bottles.backend.health import HealthChecker -from bottles.backend.logger import Logger +import logging from bottles.backend.managers.manager import Manager from bottles.backend.models.config import BottleConfig from bottles.backend.models.result import Result @@ -44,8 +44,6 @@ from bottles.frontend.dependencies_check_dialog import DependenciesCheckDialog from bottles.frontend.onboard_dialog import OnboardDialog -logging = Logger() - @Gtk.Template(resource_path="/com/usebottles/bottles/window.ui") class BottlesWindow(Adw.ApplicationWindow): @@ -82,6 +80,7 @@ def __init__(self, **kwargs): if PROFILE == "development": self.add_css_class("devel") + logging.getLogger().setLevel(logging.DEBUG) self.btn_donate.add_css_class("donate") From 5313bd4bd9fc02072088b3b607df415d3a8e310c Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Sun, 2 Feb 2025 21:39:44 -0500 Subject: [PATCH 110/146] meta: Remove JournalManager --- bottles/backend/managers/journal.py | 190 ------------------------- bottles/backend/managers/meson.build | 1 - bottles/frontend/bottles.gresource.xml | 1 - bottles/frontend/journal-dialog.blp | 80 ----------- bottles/frontend/journal_dialog.py | 103 -------------- bottles/frontend/meson.build | 2 - 6 files changed, 377 deletions(-) delete mode 100644 bottles/backend/managers/journal.py delete mode 100644 bottles/frontend/journal-dialog.blp delete mode 100644 bottles/frontend/journal_dialog.py diff --git a/bottles/backend/managers/journal.py b/bottles/backend/managers/journal.py deleted file mode 100644 index 8c471ff180b..00000000000 --- a/bottles/backend/managers/journal.py +++ /dev/null @@ -1,190 +0,0 @@ -# journal.py -# -# Copyright 2022 brombinmirko -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, in version 3 of the License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# - -import contextlib -import os -import shutil -import uuid -from datetime import datetime, timedelta - -from bottles.backend.globals import Paths -from bottles.backend.utils import yaml - - -class JournalSeverity: - """Represents the severity of a journal entry.""" - - DEBUG = "debug" - INFO = "info" - WARNING = "warning" - ERROR = "error" - CRITICAL = "critical" - CRASH = "crash" - - -class JournalManager: - """ - Store and retrieve data from the journal file (YAML). This should - contain only important Bottles events. - """ - - path = f"{Paths.base}/journal.yml" - - @staticmethod - def __get_journal() -> dict: - """Return the journal as a dictionary.""" - if not os.path.exists(JournalManager.path): - with open(JournalManager.path, "w") as f: - yaml.dump({}, f) - - with open(JournalManager.path) as f: - try: - journal = yaml.load(f) - except yaml.YAMLError: - journal_backup = f"{JournalManager.path}_{datetime.now().strftime('%Y-%m-%d_%H-%M-%S')}.bak" - shutil.copy2(JournalManager.path, journal_backup) - journal = {} - - if journal is None: - return {} - - try: - journal = { - k: v - for k, v in sorted( - journal.items(), key=lambda item: item[1]["timestamp"], reverse=True - ) - } - except (KeyError, TypeError): - journal = {} - - return journal - - @staticmethod - def __clean_old(): - """Clean old journal entries (1 month).""" - journal = JournalManager.__get_journal() - old_events = [] - latest = datetime.now().strftime("%Y-%m-%d %H:%M:%S") - - for event_id, event in journal.items(): - if event.get("timestamp", None) is None: - latest_datetime = datetime.strptime(latest, "%Y-%m-%d %H:%M:%S") - else: - latest_datetime = datetime.strptime( - event["timestamp"], "%Y-%m-%d %H:%M:%S" - ) - latest = event["timestamp"] - - if latest_datetime < datetime.now() - timedelta(days=30): - old_events.append(event_id) - - for event_id in old_events: - del journal[event_id] - - JournalManager.__save_journal(journal) - - @staticmethod - def __save_journal(journal: dict | None = None): - """Save the journal to the journal file.""" - if journal is None: - journal = JournalManager.__get_journal() - - with contextlib.suppress(IOError, OSError): - with open(JournalManager.path, "w") as f: - yaml.dump(journal, f) - - @staticmethod - def get(period: str = "today", plain: bool = False): - """ - Return all events for the given period. - Supported periods: all, today, yesterday, week, month - Set plain to True to get the response as plain text. - """ - journal = JournalManager.__get_journal() - periods = [ - "all", - "today", - "yesterday", - "week", - "month", - ] - if period not in periods: - period = "today" - - _journal = JournalManager.__filter_by_date(journal, period) - - if plain: - _journal = yaml.dump(_journal, sort_keys=False, indent=4) - - return _journal - - @staticmethod - def __filter_by_date(journal: dict, period: str): - """Filter the journal by date.""" - _journal = {} - if period == "today": - start = datetime.now().date() - end = start + timedelta(days=1) - elif period == "yesterday": - start = datetime.now().date() - timedelta(days=1) - end = start + timedelta(days=1) - elif period == "week": - start = datetime.now().date() - timedelta(days=7) - end = datetime.now().date() + timedelta(days=1) - elif period == "month": - start = datetime.now().date() - timedelta(days=30) - end = datetime.now().date() + timedelta(days=1) - elif period == "all": - return journal - else: - start = datetime.now().date() - end = start + timedelta(days=1) - - for event_id, event in journal.items(): - timestamp = datetime.strptime( - event["timestamp"], "%Y-%m-%d %H:%M:%S" - ).date() - - if start <= timestamp <= end: - _journal[event_id] = event - - return _journal - - @staticmethod - def get_event(event_id: str): - """Return the event with the given id.""" - journal = JournalManager.__get_journal() - return journal.get(event_id, None) - - @staticmethod - def write(severity: JournalSeverity, message: str): - """Write an event to the journal.""" - journal = JournalManager.__get_journal() - event_id = str(uuid.uuid4()) - now = datetime.now() - - if severity not in JournalSeverity.__dict__.values(): - severity = JournalSeverity.INFO - - journal[event_id] = { - "severity": severity, - "message": message, - "timestamp": now.strftime("%Y-%m-%d %H:%M:%S"), - } - JournalManager.__save_journal(journal) - JournalManager.__clean_old() diff --git a/bottles/backend/managers/meson.build b/bottles/backend/managers/meson.build index 0da12ec2531..d8e146a5209 100644 --- a/bottles/backend/managers/meson.build +++ b/bottles/backend/managers/meson.build @@ -9,7 +9,6 @@ bottles_sources = [ 'runtime.py', 'importer.py', 'conf.py', - 'journal.py', 'template.py', 'sandbox.py', 'epicgamesstore.py', diff --git a/bottles/frontend/bottles.gresource.xml b/bottles/frontend/bottles.gresource.xml index 91951d987cd..60f144b8f3b 100644 --- a/bottles/frontend/bottles.gresource.xml +++ b/bottles/frontend/bottles.gresource.xml @@ -40,7 +40,6 @@ mangohud-dialog.ui display-dialog.ui drives-dialog.ui - journal-dialog.ui sandbox-dialog.ui bottle-picker-dialog.ui proton-alert-dialog.ui diff --git a/bottles/frontend/journal-dialog.blp b/bottles/frontend/journal-dialog.blp deleted file mode 100644 index 9494e96b715..00000000000 --- a/bottles/frontend/journal-dialog.blp +++ /dev/null @@ -1,80 +0,0 @@ -using Gtk 4.0; -using Adw 1; - -Popover pop_menu { - Box { - orientation: vertical; - spacing: 3; - - $GtkModelButton btn_all { - text: _("All messages"); - } - - $GtkModelButton btn_critical { - text: _("Critical"); - } - - $GtkModelButton btn_error { - text: _("Errors"); - } - - $GtkModelButton btn_warning { - text: _("Warnings"); - } - - $GtkModelButton btn_info { - text: _("Info"); - } - } -} - -template $JournalDialog: Adw.Window { - default-width: 800; - default-height: 600; - destroy-with-parent: true; - - Box { - orientation: vertical; - - Adw.HeaderBar { - title-widget: Adw.WindowTitle { - title: _("Journal Browser"); - }; - - [title] - Box { - SearchEntry search_entry { - placeholder-text: _("Journal Browser"); - } - - MenuButton { - focus-on-click: false; - tooltip-text: _("Change Logging Level."); - popover: pop_menu; - - Label label_filter { - label: _("All"); - } - } - - styles [ - "linked", - ] - } - } - - ScrolledWindow { - hexpand: true; - vexpand: true; - - TreeView tree_view { - reorderable: true; - hexpand: true; - vexpand: true; - - [internal-child selection] - TreeSelection {} - } - } - } -} diff --git a/bottles/frontend/journal_dialog.py b/bottles/frontend/journal_dialog.py deleted file mode 100644 index 5540bc307ee..00000000000 --- a/bottles/frontend/journal_dialog.py +++ /dev/null @@ -1,103 +0,0 @@ -# journal_dialog.py -# -# Copyright 2025 The Bottles Contributors -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, in version 3 of the License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# - -from gi.repository import Gtk, Adw - -from bottles.backend.managers.journal import JournalManager, JournalSeverity - - -@Gtk.Template(resource_path="/com/usebottles/bottles/journal-dialog.ui") -class JournalDialog(Adw.Window): - __gtype_name__ = "JournalDialog" - - # region Widgets - tree_view = Gtk.Template.Child() - search_entry = Gtk.Template.Child() - btn_all = Gtk.Template.Child() - btn_critical = Gtk.Template.Child() - btn_error = Gtk.Template.Child() - btn_warning = Gtk.Template.Child() - btn_info = Gtk.Template.Child() - label_filter = Gtk.Template.Child() - - # endregion - - def __init__(self, **kwargs): - super().__init__(**kwargs) - - self.journal = JournalManager.get().items() - self.store = Gtk.ListStore(str, str, str) - - # connect signals - self.search_entry.connect("search-changed", self.on_search_changed) - self.btn_all.connect("clicked", self.filter_results, "") - self.btn_critical.connect( - "clicked", self.filter_results, JournalSeverity.CRITICAL - ) - self.btn_error.connect("clicked", self.filter_results, JournalSeverity.ERROR) - self.btn_warning.connect( - "clicked", self.filter_results, JournalSeverity.WARNING - ) - self.btn_info.connect("clicked", self.filter_results, JournalSeverity.INFO) - - self.populate_tree_view() - - def populate_tree_view(self, query="", severity=""): - self.store.clear() - - colors = { - JournalSeverity.CRITICAL: "#db1600", - JournalSeverity.ERROR: "#db6600", - JournalSeverity.WARNING: "#dba100", - JournalSeverity.INFO: "#3283a8", - JournalSeverity.CRASH: "#db1600", - } - - for _, value in self.journal: - if query.lower() in value["message"].lower() and ( - severity == "" or severity == value["severity"] - ): - self.store.append( - [ - '{}'.format( - colors[value["severity"]], value["severity"].capitalize() - ), - value["timestamp"], - value["message"], - ] - ) - - self.tree_view.set_model(self.store) - self.tree_view.set_search_column(1) - - self.tree_view.append_column( - Gtk.TreeViewColumn("Severity", Gtk.CellRendererText(), markup=0) - ) - self.tree_view.append_column( - Gtk.TreeViewColumn("Timestamp", Gtk.CellRendererText(), text=1) - ) - self.tree_view.append_column( - Gtk.TreeViewColumn("Message", Gtk.CellRendererText(), text=2) - ) - - def on_search_changed(self, entry): - self.populate_tree_view(entry.get_text()) - - def filter_results(self, _, severity): - self.populate_tree_view(self.search_entry.get_text(), severity) - label = severity if severity != "" else "all" - self.label_filter.set_text(label.capitalize()) diff --git a/bottles/frontend/meson.build b/bottles/frontend/meson.build index a98e0a13563..780f1bff3f4 100644 --- a/bottles/frontend/meson.build +++ b/bottles/frontend/meson.build @@ -25,7 +25,6 @@ blueprints = custom_target('blueprints', 'duplicate-dialog.blp', 'environment-variables-dialog.blp', 'gamescope-dialog.blp', - 'journal-dialog.blp', 'launch-options-dialog.blp', 'proton-alert-dialog.blp', 'rename-program-dialog.blp', @@ -121,7 +120,6 @@ bottles_sources = [ 'mangohud_dialog.py', 'display_dialog.py', 'generic_cli.py', - 'journal_dialog.py', 'bottle_picker_dialog.py', 'proton_alert_dialog.py', 'sandbox_dialog.py', From 4a5440671a8bb9fd70592daf3cee94396f50b9c2 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Sun, 2 Feb 2025 22:11:55 -0500 Subject: [PATCH 111/146] frontend: Remove QueueManager --- bottles/frontend/bottle_details_view.py | 2 -- bottles/frontend/dependency_entry_row.py | 3 --- bottles/frontend/details_dependencies_view.py | 1 - bottles/frontend/details_preferences_page.py | 17 ----------------- bottles/frontend/display_dialog.py | 9 --------- 5 files changed, 32 deletions(-) diff --git a/bottles/frontend/bottle_details_view.py b/bottles/frontend/bottle_details_view.py index 321b49b2d0a..8177b8d828c 100644 --- a/bottles/frontend/bottle_details_view.py +++ b/bottles/frontend/bottle_details_view.py @@ -20,7 +20,6 @@ from gi.repository import Gtk, Adw, GLib -from bottles.backend.managers.queue import QueueManager from bottles.backend.models.config import BottleConfig from bottles.backend.utils.threading import RunAsync @@ -69,7 +68,6 @@ def __init__(self, window, config: BottleConfig | None = None, **kwargs): self.window = window self.manager = window.manager self.config = config - self.queue = QueueManager(add_fn=self.lock_back, end_fn=self.unlock_back) self.view_bottle = BottleDetailsPage(self, config) self.view_dependencies = DetailsDependenciesView(self, config) diff --git a/bottles/frontend/dependency_entry_row.py b/bottles/frontend/dependency_entry_row.py index 99646567f2e..b1ce08a7cb5 100644 --- a/bottles/frontend/dependency_entry_row.py +++ b/bottles/frontend/dependency_entry_row.py @@ -53,7 +53,6 @@ def __init__(self, window, config: BottleConfig, dependency, plain=False, **kwar self.manager = window.manager self.config = config self.dependency = dependency - self.queue = window.page_details.queue if plain: """ @@ -137,7 +136,6 @@ def install_dependency(self, _widget): and set the dependency as installed in the bottle configuration """ - self.queue.add_task() self.get_parent().set_sensitive(False) self.btn_install.set_visible(False) self.spinner.show() @@ -170,7 +168,6 @@ def set_install_status(self, result: Result, error=None): if the installation is successful, or uninstalled if the uninstallation is successful. """ - self.queue.end_task() if result is not None and result.status: if self.config.Parameters.versioning_automatic: self.window.page_details.view_versioning.update() diff --git a/bottles/frontend/details_dependencies_view.py b/bottles/frontend/details_dependencies_view.py index 30e8412c4d8..d9b1572ee20 100644 --- a/bottles/frontend/details_dependencies_view.py +++ b/bottles/frontend/details_dependencies_view.py @@ -52,7 +52,6 @@ def __init__(self, details, config: BottleConfig, **kwargs): self.window = details.window self.manager = details.window.manager self.config = config - self.queue = details.queue self.ev_controller.connect("key-released", self.__search_dependencies) diff --git a/bottles/frontend/details_preferences_page.py b/bottles/frontend/details_preferences_page.py index e6178ea436e..03491fe1c0d 100644 --- a/bottles/frontend/details_preferences_page.py +++ b/bottles/frontend/details_preferences_page.py @@ -129,7 +129,6 @@ def __init__(self, details, config, **kwargs): self.window = details.window self.manager = details.window.manager self.config = config - self.queue = details.queue self.details = details if not gamemode_available or not Xdp.Portal.running_under_sandbox(): @@ -541,7 +540,6 @@ def __show_display_settings(self, widget): parent_window=self.window, config=self.config, details=self.details, - queue=self.queue, widget=widget, spinner_display=self.spinner_display, ) @@ -570,7 +568,6 @@ def __set_sync_type(self, *_args): "esync", "fsync", ] - self.queue.add_task() self.combo_sync.set_sensitive(False) RunAsync( self.manager.update_config, @@ -580,11 +577,9 @@ def __set_sync_type(self, *_args): scope="Parameters", ) self.combo_sync.set_sensitive(True) - self.queue.end_task() def __toggle_nvapi(self, widget=False, state=False): """Install/Uninstall NVAPI from the bottle""" - self.queue.add_task() self.set_nvapi_status(pending=True) RunAsync( @@ -648,7 +643,6 @@ def update(result: Result[dict], error=False): ) set_widgets_status(True) - self.queue.end_task() set_widgets_status(False) runner = self.manager.runners_available[self.combo_runner.get_selected()] @@ -660,7 +654,6 @@ def run_task(status=True): self.combo_runner.handler_unblock_by_func(self.__set_runner) return - self.queue.add_task() RunAsync( Runner.runner_update, callback=update, @@ -688,7 +681,6 @@ def __dll_component_task_func(self, *args, **kwargs): def __set_dxvk(self, *_args): """Set the DXVK version to use for the bottle""" self.set_dxvk_status(pending=True) - self.queue.add_task() if (self.combo_dxvk.get_selected()) == 0: self.set_dxvk_status(pending=True) @@ -728,7 +720,6 @@ def __set_dxvk(self, *_args): def __set_vkd3d(self, *_args): """Set the VKD3D version to use for the bottle""" self.set_vkd3d_status(pending=True) - self.queue.add_task() if (self.combo_vkd3d.get_selected()) == 0: self.set_vkd3d_status(pending=True) @@ -768,7 +759,6 @@ def __set_vkd3d(self, *_args): def __set_nvapi(self, *_args): """Set the NVAPI version to use for the bottle""" self.set_nvapi_status(pending=True) - self.queue.add_task() self.switch_nvapi.set_active(True) @@ -790,7 +780,6 @@ def __set_nvapi(self, *_args): def __set_latencyflex(self, *_args): """Set the latency flex value""" - self.queue.add_task() if self.combo_latencyflex.get_selected() == 0: RunAsync( task_func=self.manager.install_dll_component, @@ -830,9 +819,7 @@ def update(result, error=False): self.spinner_windows.stop() self.spinner_windows.set_visible(False) self.combo_windows.set_sensitive(True) - self.queue.end_task() - self.queue.add_task() self.spinner_windows.start() self.spinner_windows.set_visible(True) self.combo_windows.set_sensitive(False) @@ -867,7 +854,6 @@ def set_dxvk_status(self, status=None, error=None, pending=False): else: self.spinner_dxvk.stop() self.spinner_dxvk.set_visible(False) - self.queue.end_task() @GtkUtils.run_in_main_loop def set_vkd3d_status(self, status=None, error=None, pending=False): @@ -879,7 +865,6 @@ def set_vkd3d_status(self, status=None, error=None, pending=False): else: self.spinner_vkd3d.stop() self.spinner_vkd3d.set_visible(False) - self.queue.end_task() @GtkUtils.run_in_main_loop def set_nvapi_status(self, status=None, error=None, pending=False): @@ -896,7 +881,6 @@ def set_nvapi_status(self, status=None, error=None, pending=False): self.spinner_nvapibool.stop() self.spinner_nvapi.set_visible(False) self.spinner_nvapibool.set_visible(False) - self.queue.end_task() @GtkUtils.run_in_main_loop def set_latencyflex_status(self, status=None, error=None, pending=False): @@ -908,7 +892,6 @@ def set_latencyflex_status(self, status=None, error=None, pending=False): else: self.spinner_latencyflex.stop() self.spinner_latencyflex.set_visible(False) - self.queue.end_task() def __set_steam_rules(self): """Set the Steam Environment specific rules""" diff --git a/bottles/frontend/display_dialog.py b/bottles/frontend/display_dialog.py index 9df9dd5c00f..d792f072e00 100644 --- a/bottles/frontend/display_dialog.py +++ b/bottles/frontend/display_dialog.py @@ -54,7 +54,6 @@ def __init__( self.window = parent_window self.manager = parent_window.manager self.config = config - self.queue = queue self.widget = widget self.spinner_display = spinner_display @@ -96,7 +95,6 @@ def __idle_save(self, *args): """Queue system""" self.started = 0 - self.queued = 0 self.completed = 0 def add_queue(): @@ -104,17 +102,10 @@ def add_queue(): self.window.show_toast(_("Updating display settings, please wait…")) self.spinner_display.start() self.started = 1 - self.queue.add_task() self.widget.set_sensitive(False) - self.queued += 1 def complete_queue(): self.completed += 1 - if self.queued == self.completed: - self.widget.set_sensitive(True) - self.spinner_display.stop() - self.window.show_toast(_("Display settings updated")) - self.queue.end_task() if ( self.expander_virtual_desktop.get_enable_expansion() From 8e00264d4d3bea38ffb88b782cbff3f7a0aff72b Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Sun, 2 Feb 2025 22:13:04 -0500 Subject: [PATCH 112/146] backend: Remove QueueManager --- bottles/backend/managers/meson.build | 1 - bottles/backend/managers/queue.py | 34 ---------------------------- 2 files changed, 35 deletions(-) delete mode 100644 bottles/backend/managers/queue.py diff --git a/bottles/backend/managers/meson.build b/bottles/backend/managers/meson.build index d8e146a5209..d988ba7f590 100644 --- a/bottles/backend/managers/meson.build +++ b/bottles/backend/managers/meson.build @@ -14,7 +14,6 @@ bottles_sources = [ 'epicgamesstore.py', 'ubisoftconnect.py', 'origin.py', - 'queue.py', 'steamgriddb.py', 'thumbnail.py' ] diff --git a/bottles/backend/managers/queue.py b/bottles/backend/managers/queue.py deleted file mode 100644 index 450f1d95fdb..00000000000 --- a/bottles/backend/managers/queue.py +++ /dev/null @@ -1,34 +0,0 @@ -# queue.py -# -# Copyright 2022 brombinmirko -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, in version 3 of the License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# - - -class QueueManager: - __queue = 0 - - def __init__(self, end_fn, add_fn=None): - self.__add_fn = add_fn - self.__end_fn = end_fn - - def add_task(self): - self.__queue += 1 - if self.__add_fn and self.__queue == 1: - self.__add_fn() - - def end_task(self): - self.__queue -= 1 - if self.__queue <= 0: - self.__end_fn() From b6a963500222dddde84ee4c779ac712b8206ba79 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Sun, 2 Feb 2025 22:14:24 -0500 Subject: [PATCH 113/146] frontend: Remove RuntimeManager --- bottles/frontend/details_preferences_page.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/bottles/frontend/details_preferences_page.py b/bottles/frontend/details_preferences_page.py index 03491fe1c0d..ccd6b1f8957 100644 --- a/bottles/frontend/details_preferences_page.py +++ b/bottles/frontend/details_preferences_page.py @@ -33,7 +33,6 @@ ) import logging from bottles.backend.managers.library import LibraryManager -from bottles.backend.managers.runtime import RuntimeManager from bottles.backend.models.config import BottleConfig from bottles.backend.models.enum import Arch from bottles.backend.models.result import Result @@ -246,12 +245,6 @@ def __init__(self, details, config, **kwargs): self.row_nvapi.set_visible(is_nvidia_gpu) self.combo_nvapi.set_visible(is_nvidia_gpu) - if RuntimeManager.get_runtimes("steam"): - self.row_steam_runtime.set_visible(True) - self.switch_steam_runtime.connect( - "state-set", self.__toggle_feature_cb, "use_steam_runtime" - ) - """Toggle some utilities according to its availability""" self.switch_gamemode.set_sensitive(gamemode_available) self.switch_gamescope.set_sensitive(gamescope_available) From 86e2358d04932e372c7f43d552c91920c38b5670 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Sun, 2 Feb 2025 22:16:22 -0500 Subject: [PATCH 114/146] backend: Remove RuntimeManager --- bottles/backend/managers/meson.build | 1 - bottles/backend/managers/runtime.py | 119 --------------------------- bottles/backend/runner.py | 14 ---- bottles/backend/wine/winecommand.py | 32 ------- 4 files changed, 166 deletions(-) delete mode 100644 bottles/backend/managers/runtime.py diff --git a/bottles/backend/managers/meson.build b/bottles/backend/managers/meson.build index d988ba7f590..355b0bb2206 100644 --- a/bottles/backend/managers/meson.build +++ b/bottles/backend/managers/meson.build @@ -6,7 +6,6 @@ bottles_sources = [ 'backup.py', 'library.py', 'manager.py', - 'runtime.py', 'importer.py', 'conf.py', 'template.py', diff --git a/bottles/backend/managers/runtime.py b/bottles/backend/managers/runtime.py deleted file mode 100644 index 86b14201e64..00000000000 --- a/bottles/backend/managers/runtime.py +++ /dev/null @@ -1,119 +0,0 @@ -# runtime.py -# -# Copyright 2022 brombinmirko -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, in version 3 of the License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# - -import os -from functools import lru_cache - -from bottles.backend.globals import Paths - - -class RuntimeManager: - @staticmethod - @lru_cache - def get_runtimes(_filter: str = "bottles"): - runtimes = { - "bottles": RuntimeManager.__get_bottles_runtime(), - } - - if _filter == "steam": - if len(runtimes.get("steam", {})) == 0: - return False - - return runtimes.get(_filter, False) - - @staticmethod - def get_runtime_env(_filter: str = "bottles"): - runtime = RuntimeManager.get_runtimes(_filter) - env = "" - - if runtime: - for p in runtime: - if "EasyAntiCheatRuntime" in p or "BattlEyeRuntime" in p: - continue - env += f":{p}" - - else: - return False - - ld = os.environ.get("LD_LIBRARY_PATH") - if ld: - env += f":{ld}" - - return env - - @staticmethod - def get_eac(): - runtime = RuntimeManager.get_runtimes("bottles") - - if runtime: - for p in runtime: - if "EasyAntiCheatRuntime" in p: - return p - - return False - - @staticmethod - def get_be(): - runtime = RuntimeManager.get_runtimes("bottles") - - if runtime: - for p in runtime: - if "BattlEyeRuntime" in p: - return p - - return False - - @staticmethod - def __get_runtime(paths: list, structure: list): - def check_structure(found, expected): - for e in expected: - if e not in found: - return False - return True - - for runtime_path in paths: - if not os.path.exists(runtime_path): - continue - - structure_found = [] - for root, dirs, files in os.walk(runtime_path): - for d in dirs: - structure_found.append(d) - - if not check_structure(structure_found, structure): - return [] - - res = [f"{runtime_path}/{s}" for s in structure] - eac_path = os.path.join(runtime_path, "EasyAntiCheatRuntime") - be_path = os.path.join(runtime_path, "BattlEyeRuntime") - - if os.path.isdir(eac_path): - res.append(eac_path) - - if os.path.isdir(be_path): - res.append(be_path) - - return res - - return False - - @staticmethod - def __get_bottles_runtime(): - paths = ["/app/etc/runtime", Paths.runtimes] - structure = ["lib", "lib32"] - - return RuntimeManager.__get_runtime(paths, structure) diff --git a/bottles/backend/runner.py b/bottles/backend/runner.py index f37a7e03002..94e4baffd09 100644 --- a/bottles/backend/runner.py +++ b/bottles/backend/runner.py @@ -19,7 +19,6 @@ from typing import TYPE_CHECKING import logging -from bottles.backend.managers.runtime import RuntimeManager from bottles.backend.models.config import BottleConfig from bottles.backend.models.result import Result from bottles.backend.utils.manager import ManagerUtils @@ -77,17 +76,4 @@ def runner_update( if config.Parameters.vkd3d: manager.install_dll_component(config, "vkd3d", overrides_only=True) - """ - enable Steam runtime if using Proton. - - NOTE: Official Proton runners need to be launched with the Steam Runtime to works - properly, since it relies on a lot of libraries that should not be present on - the host system. There are some exceptions, like the Soda and Wine-GE runners, - which are built to work without the Steam Runtime. - """ - if SteamUtils.is_proton( - ManagerUtils.get_runner_path(runner) - ) and RuntimeManager.get_runtimes("steam"): - manager.update_config(config, "use_steam_runtime", True, "Parameters") - return Result(status=True, data={"config": up_config}) diff --git a/bottles/backend/wine/winecommand.py b/bottles/backend/wine/winecommand.py index 30fb1799c06..334753bb36d 100644 --- a/bottles/backend/wine/winecommand.py +++ b/bottles/backend/wine/winecommand.py @@ -14,7 +14,6 @@ vmtouch_available, ) import logging -from bottles.backend.managers.runtime import RuntimeManager from bottles.backend.managers.sandbox import SandboxManager from bottles.backend.models.config import BottleConfig from bottles.backend.models.result import Result @@ -221,37 +220,6 @@ def get_env( if not return_steam_env: dll_overrides.append("winemenubuilder=''") - # Get Runtime libraries - if ( - (params.use_runtime or params.use_eac_runtime or params.use_be_runtime) - and not self.terminal - and not return_steam_env - ): - _rb = RuntimeManager.get_runtime_env("bottles") - if _rb: - _eac = RuntimeManager.get_eac() - _be = RuntimeManager.get_be() - - if params.use_runtime: - logging.info("Using Bottles runtime") - ld += _rb - - if ( - _eac and not self.minimal - ): # NOTE: should check for runner compatibility with "eac" (?) - logging.info("Using EasyAntiCheat runtime") - env.add("PROTON_EAC_RUNTIME", _eac) - dll_overrides.append("easyanticheat_x86,easyanticheat_x64=b,n") - - if ( - _be and not self.minimal - ): # NOTE: should check for runner compatibility with "be" (?) - logging.info("Using BattlEye runtime") - env.add("PROTON_BATTLEYE_RUNTIME", _be) - dll_overrides.append("beclient,beclient_x64=b,n") - else: - logging.warning("Bottles runtime was requested but not found") - # Get Runner libraries if arch == "win64": runner_libs = [ From 30450a939b0b685a8713f191466a00211fb912cf Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Sun, 2 Feb 2025 22:19:14 -0500 Subject: [PATCH 115/146] chore: Remove tests It's not even being used anymore. --- bottles/tests/__init__.py | 0 bottles/tests/backend/__init__.py | 0 bottles/tests/backend/manager/__init__.py | 0 bottles/tests/backend/manager/test_manager.py | 15 -- bottles/tests/backend/state/__init__.py | 0 bottles/tests/backend/state/test_events.py | 145 ------------------ bottles/tests/backend/utils/__init__.py | 0 bottles/tests/backend/utils/test_generic.py | 25 --- 8 files changed, 185 deletions(-) delete mode 100644 bottles/tests/__init__.py delete mode 100644 bottles/tests/backend/__init__.py delete mode 100644 bottles/tests/backend/manager/__init__.py delete mode 100644 bottles/tests/backend/manager/test_manager.py delete mode 100644 bottles/tests/backend/state/__init__.py delete mode 100644 bottles/tests/backend/state/test_events.py delete mode 100644 bottles/tests/backend/utils/__init__.py delete mode 100644 bottles/tests/backend/utils/test_generic.py diff --git a/bottles/tests/__init__.py b/bottles/tests/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/bottles/tests/backend/__init__.py b/bottles/tests/backend/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/bottles/tests/backend/manager/__init__.py b/bottles/tests/backend/manager/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/bottles/tests/backend/manager/test_manager.py b/bottles/tests/backend/manager/test_manager.py deleted file mode 100644 index 751b882a0ca..00000000000 --- a/bottles/tests/backend/manager/test_manager.py +++ /dev/null @@ -1,15 +0,0 @@ -"""Core Manager tests""" - -from bottles.backend.managers.manager import Manager -from bottles.backend.utils.gsettings_stub import GSettingsStub - - -def test_manager_is_singleton(): - assert Manager() is Manager(), "Manager should be singleton object" - assert Manager() is Manager( - g_settings=GSettingsStub() - ), "Manager should be singleton even with different argument" - - -def test_manager_default_gsettings_stub(): - assert Manager().settings.get_boolean("anything") is False diff --git a/bottles/tests/backend/state/__init__.py b/bottles/tests/backend/state/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/bottles/tests/backend/state/test_events.py b/bottles/tests/backend/state/test_events.py deleted file mode 100644 index c216d8ac20a..00000000000 --- a/bottles/tests/backend/state/test_events.py +++ /dev/null @@ -1,145 +0,0 @@ -"""EventManager tests""" - -import time -from enum import Enum -from threading import Thread -import pytest - -from bottles.backend.state import EventManager - - -class Events(Enum): - SimpleEvent = "simple.event" - WaitAfterDone = "wait_after_done.event" - SetResetEvent = "set_reset.event" - WaitSingleton = "wait_singleton.event" - DoneSingleton = "done_singleton.event" - CorrectFlagDone = "correct_flag_done.event" - - -def approx_time(start, target): - epsilon = 0.010 # 5 ms window - variation = time.time() - start - target - result = -epsilon / 2 <= variation <= epsilon / 2 - if not result: - print(f"Start: {start}") - print(f"End: {variation + start + target}") - print(f"Variation: {variation}") - return result - - -def test_simple_event(): - start_time = time.time() - - def t1_func(): - EventManager.wait(Events.SimpleEvent) - - t1 = Thread(target=t1_func) - t1.start() - - time.sleep(0.2) - EventManager.done(Events.SimpleEvent) - - t1.join() - assert approx_time(start_time, 0.2) - - -def test_wait_after_done_event(): - start_time = time.time() - EventManager.done(Events.WaitAfterDone) - - EventManager.wait(Events.WaitAfterDone) - assert approx_time(start_time, 0) - - -@pytest.mark.filterwarnings("error") -def test_set_reset(): - start_time = time.time() - - def t1_func(): - start_time_t1 = time.time() - EventManager.wait(Events.SetResetEvent) - assert approx_time(start_time_t1, 0.1) - - def t2_func(): - start_time_t1 = time.time() - EventManager.wait(Events.SetResetEvent) - assert approx_time(start_time_t1, 0) - - t1 = Thread(target=t1_func) - t1.start() - - time.sleep(0.1) - EventManager.done(Events.SetResetEvent) - - # Assert wait for 0.1s - t1.join() - - t2 = Thread(target=t2_func) - t2.start() - # Assert wait for 0s - t2.join() - - time.sleep(0.1) - - EventManager.reset(Events.SetResetEvent) - - t1 = Thread(target=t1_func) - t1.start() - - time.sleep(0.1) - EventManager.done(Events.SetResetEvent) - - # Assert wait for 0.1s - t1.join() - assert approx_time(start_time, 0.3) - - -def test_event_singleton_wait(): - EventManager._EVENTS = {} - - def wait_thread(): - EventManager.wait(Events.WaitSingleton) - - def wait_thread_by_value(): - EventManager.wait(Events("wait_singleton.event")) - - t1 = Thread(target=wait_thread) - t1.start() - - t2 = Thread(target=wait_thread) - t2.start() - - t3 = Thread(target=wait_thread_by_value) - t3.start() - - assert len(EventManager._EVENTS) == 1 - - EventManager.done(Events.WaitSingleton) - t1.join() - t2.join() - t3.join() - - -def test_event_singleton_done_reset(): - EventManager._EVENTS = {} - - EventManager.done(Events.DoneSingleton) - EventManager.done(Events.DoneSingleton) - assert len(EventManager._EVENTS) == 1 - - EventManager.reset(Events.DoneSingleton) - assert len(EventManager._EVENTS) == 1 - - EventManager.reset(Events.DoneSingleton) - assert len(EventManager._EVENTS) == 1 - - -def test_correct_internal_flag(): - EventManager.done(Events.CorrectFlagDone) - - assert EventManager._EVENTS[Events.CorrectFlagDone].is_set() - - EventManager.reset(Events.CorrectFlagDone) - - assert not EventManager._EVENTS[Events.CorrectFlagDone].is_set() diff --git a/bottles/tests/backend/utils/__init__.py b/bottles/tests/backend/utils/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/bottles/tests/backend/utils/test_generic.py b/bottles/tests/backend/utils/test_generic.py deleted file mode 100644 index aebd901816b..00000000000 --- a/bottles/tests/backend/utils/test_generic.py +++ /dev/null @@ -1,25 +0,0 @@ -import pytest - -from bottles.backend.utils.generic import detect_encoding - - -# CP932 is superset of Shift-JIS, which is default codec for Japanese in Windows -# GBK is default codec for Chinese in Windows -@pytest.mark.parametrize( - "text, hint, codec", - [ - ("Hello, world!", None, "ascii"), - (" ", None, "ascii"), - ("Привет, мир!", None, "windows-1251"), - ("こんにちは、世界!", "ja_JP", "cp932"), - ("こんにちは、世界!", "ja_JP.utf-8", "utf-8"), - ("你好,世界!", "zh_CN", "gbk"), - ("你好,世界!", "zh_CN.UTF-8", "utf-8"), - ("你好,世界!", "zh_CN.invalid_fallback", "gbk"), - ("", None, "utf-8"), - ], -) -def test_detect_encoding(text: str, hint: str | None, codec: str | None): - text_bytes = text.encode(codec) - guess = detect_encoding(text_bytes, hint) - assert guess.lower() == codec.lower() From 0a1d25f3b0da34e39f7a181dccc7fbc9b6671e4f Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Sun, 2 Feb 2025 22:26:51 -0500 Subject: [PATCH 116/146] frontend: Remove ImporterManager --- bottles/frontend/bottles.gresource.xml | 2 - bottles/frontend/importer-row.blp | 75 ----------- bottles/frontend/importer-view.blp | 75 ----------- bottles/frontend/importer_row.py | 82 ------------ bottles/frontend/importer_view.py | 167 ------------------------- bottles/frontend/main.py | 4 - bottles/frontend/meson.build | 4 - bottles/frontend/window.blp | 7 -- bottles/frontend/window.py | 7 -- 9 files changed, 423 deletions(-) delete mode 100644 bottles/frontend/importer-row.blp delete mode 100644 bottles/frontend/importer-view.blp delete mode 100644 bottles/frontend/importer_row.py delete mode 100644 bottles/frontend/importer_view.py diff --git a/bottles/frontend/bottles.gresource.xml b/bottles/frontend/bottles.gresource.xml index 60f144b8f3b..62dd7b1e21f 100644 --- a/bottles/frontend/bottles.gresource.xml +++ b/bottles/frontend/bottles.gresource.xml @@ -13,7 +13,6 @@ task-row.ui dependency-entry-row.ui program-row.ui - importer-row.ui dll-override-entry.ui env-var-entry.ui component-entry-row.ui @@ -26,7 +25,6 @@ details-preferences-page.ui details-task-manager-view.ui preferences.ui - importer-view.ui library-view.ui launch-options-dialog.ui dll-overrides-dialog.ui diff --git a/bottles/frontend/importer-row.blp b/bottles/frontend/importer-row.blp deleted file mode 100644 index 609124e57ae..00000000000 --- a/bottles/frontend/importer-row.blp +++ /dev/null @@ -1,75 +0,0 @@ -using Gtk 4.0; -using Adw 1; - -Popover pop_actions { - styles [ - "menu", - ] - - Box { - orientation: vertical; - spacing: 3; - - $GtkModelButton btn_browse { - text: _("Browse Files"); - } - } -} - -template $ImporterRow: Adw.ActionRow { - /* Translators: A Wine prefix is a separate environment (C:\ drive) for the Wine program */ - title: _("Wine prefix name"); - - Box { - spacing: 6; - - Label label_manager { - valign: center; - label: _("Manager"); - - styles [ - "tag", - "caption", - ] - } - - Image img_lock { - visible: false; - tooltip-text: _("This Wine prefix was already imported in Bottles."); - valign: center; - icon-name: "channel-secure-symbolic"; - - styles [ - "tag", - "caption", - ] - } - - Button btn_import { - valign: center; - - Image { - icon-name: "document-save-symbolic"; - } - - styles [ - "flat", - ] - } - - Separator { - margin-top: 12; - margin-bottom: 12; - } - - MenuButton { - valign: center; - popover: pop_actions; - icon-name: "view-more-symbolic"; - - styles [ - "flat", - ] - } - } -} diff --git a/bottles/frontend/importer-view.blp b/bottles/frontend/importer-view.blp deleted file mode 100644 index 7cd80ccd7b1..00000000000 --- a/bottles/frontend/importer-view.blp +++ /dev/null @@ -1,75 +0,0 @@ -using Gtk 4.0; -using Adw 1; - -template $ImporterView: Adw.Bin { - Box { - orientation: vertical; - - HeaderBar headerbar { - title-widget: Adw.WindowTitle window_title {}; - - [start] - Button btn_back { - tooltip-text: _("Go Back"); - icon-name: "go-previous-symbolic"; - } - - [end] - Box box_actions { - MenuButton btn_import_backup { - tooltip-text: _("Import a Bottle backup"); - popover: pop_backup; - icon-name: "document-send-symbolic"; - } - - Button btn_find_prefixes { - tooltip-text: _("Search again for prefixes"); - icon-name: "view-refresh-symbolic"; - } - } - } - - Adw.PreferencesPage { - Adw.StatusPage status_page { - vexpand: true; - icon-name: "document-save-symbolic"; - title: _("No Prefixes Found"); - description: _("No external prefixes were found. Does Bottles have access to them?\nUse the icon on the top to import a bottle from a backup."); - } - - Adw.PreferencesGroup group_prefixes { - visible: false; - - ListBox list_prefixes { - styles [ - "boxed-list", - ] - } - } - } - } -} - -Popover pop_backup { - styles [ - "menu", - ] - - Box { - orientation: vertical; - margin-top: 6; - margin-bottom: 6; - margin-start: 6; - margin-end: 6; - - $GtkModelButton btn_import_config { - tooltip-text: _("This is just the bottle configuration, it\'s perfect if you want to create a new one but without personal files."); - text: _("Configuration"); - } - - $GtkModelButton btn_import_full { - tooltip-text: _("This is the complete archive of your bottle, including personal files."); - text: _("Full Archive"); - } - } -} diff --git a/bottles/frontend/importer_row.py b/bottles/frontend/importer_row.py deleted file mode 100644 index 106bb04af5a..00000000000 --- a/bottles/frontend/importer_row.py +++ /dev/null @@ -1,82 +0,0 @@ -# importer_row.py -# -# Copyright 2025 The Bottles Contributors -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, in version 3 of the License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# - -from gettext import gettext as _ - -from gi.repository import Gtk, Adw - -from bottles.backend.utils.manager import ManagerUtils -from bottles.backend.utils.threading import RunAsync -from bottles.frontend.gtk import GtkUtils - - -@Gtk.Template(resource_path="/com/usebottles/bottles/importer-row.ui") -class ImporterRow(Adw.ActionRow): - __gtype_name__ = "ImporterRow" - - # region Widgets - label_manager = Gtk.Template.Child() - btn_import = Gtk.Template.Child() - btn_browse = Gtk.Template.Child() - img_lock = Gtk.Template.Child() - - # endregion - - def __init__(self, im_manager, prefix, **kwargs): - super().__init__(**kwargs) - - # common variables and references - self.window = im_manager.window - self.import_manager = im_manager.import_manager - self.prefix = prefix - - # populate widgets - self.set_title(prefix.get("Name")) - self.label_manager.set_text(prefix.get("Manager")) - - if prefix.get("Lock"): - self.img_lock.set_visible(True) - - self.label_manager.add_css_class("tag-%s" % prefix.get("Manager").lower()) - - # connect signals - self.btn_browse.connect("clicked", self.browse_wineprefix) - self.btn_import.connect("clicked", self.import_wineprefix) - - def browse_wineprefix(self, widget): - ManagerUtils.browse_wineprefix(self.prefix) - - def import_wineprefix(self, widget): - @GtkUtils.run_in_main_loop - def set_imported(result, error=False): - self.btn_import.set_visible(result.ok) - self.img_lock.set_visible(result.ok) - - if result.ok: - self.window.show_toast( - _('"{0}" imported').format(self.prefix.get("Name")) - ) - - self.set_sensitive(True) - - self.set_sensitive(False) - - RunAsync( - self.import_manager.import_wineprefix, - callback=set_imported, - wineprefix=self.prefix, - ) diff --git a/bottles/frontend/importer_view.py b/bottles/frontend/importer_view.py deleted file mode 100644 index 4a2256f2202..00000000000 --- a/bottles/frontend/importer_view.py +++ /dev/null @@ -1,167 +0,0 @@ -# importer_view.py -# -# Copyright 2025 The Bottles Contributors -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, in version 3 of the License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# - -from gettext import gettext as _ - -from gi.repository import Gtk, Adw - -from bottles.backend.managers.backup import BackupManager -from bottles.backend.utils.threading import RunAsync -from bottles.frontend.filters import add_yaml_filters, add_all_filters -from bottles.frontend.gtk import GtkUtils -from bottles.frontend.importer_row import ImporterRow - - -@Gtk.Template(resource_path="/com/usebottles/bottles/importer-view.ui") -class ImporterView(Adw.Bin): - __gtype_name__ = "ImporterView" - - # region Widgets - list_prefixes = Gtk.Template.Child() - btn_find_prefixes = Gtk.Template.Child() - btn_import_config = Gtk.Template.Child() - btn_import_full = Gtk.Template.Child() - btn_back = Gtk.Template.Child() - group_prefixes = Gtk.Template.Child() - status_page = Gtk.Template.Child() - - # endregion - - def __init__(self, window, **kwargs): - super().__init__(**kwargs) - - # common variables and references - self.window = window - self.manager = window.manager - self.import_manager = window.manager.import_manager - - # connect signals - self.btn_back.connect("clicked", self.go_back) - self.btn_find_prefixes.connect("clicked", self.__find_prefixes) - self.btn_import_full.connect("clicked", self.__import_full_bck) - self.btn_import_config.connect("clicked", self.__import_config_bck) - - def __find_prefixes(self, widget): - """ - This function remove all entries from the list_prefixes, ask the - manager to find all prefixes in the system and add them to the list - """ - - @GtkUtils.run_in_main_loop - def update(result, error=False): - widget.set_sensitive(True) - if result.ok: - wineprefixes = result.data.get("wineprefixes") - if len(wineprefixes) == 0: - return - - self.status_page.set_visible(False) - self.group_prefixes.set_visible(True) - - while self.list_prefixes.get_first_child(): - _w = self.list_prefixes.get_first_child() - self.list_prefixes.remove(_w) - - for prefix in result.data.get("wineprefixes"): - self.list_prefixes.append(ImporterRow(self, prefix)) - - widget.set_sensitive(False) - - RunAsync(self.import_manager.search_wineprefixes, callback=update) - - @GtkUtils.run_in_main_loop - def __finish(self, result, error=False): - if result.ok: - self.window.show_toast(_("Backup imported successfully")) - else: - self.window.show_toast(_("Import failed")) - - def __import_full_bck(self, *_args): - """ - This function shows a dialog to the user, from which it can choose an - archive backup to import into Bottles. It supports only .tar.gz files - as Bottles export bottles in this format. Once selected, it will - be imported. - """ - - def set_path(_dialog, response): - if response != Gtk.ResponseType.ACCEPT: - return - - self.window.show_toast(_("Importing backup…")) - RunAsync( - task_func=BackupManager.import_backup, - callback=self.__finish, - scope="full", - path=dialog.get_file().get_path(), - ) - - dialog = Gtk.FileChooserNative.new( - title=_("Select a Backup Archive"), - action=Gtk.FileChooserAction.OPEN, - parent=self.window, - accept_label=_("Import"), - ) - - filter = Gtk.FileFilter() - filter.set_name("GNU Gzip Archive") - # TODO: Investigate why `filter.add_mime_type(...)` does not show filter in all distributions. - # Intended MIME types are: - # - `application/gzip` - filter.add_pattern("*.gz") - - dialog.add_filter(filter) - add_all_filters(dialog) - dialog.set_modal(True) - dialog.connect("response", set_path) - dialog.show() - - def __import_config_bck(self, *_args): - """ - This function shows a dialog to the user, from which it can choose an - archive backup to import into Bottles. It supports only .yml files - which are the Bottles' configuration file. Once selected, it will - be imported. - """ - - def set_path(_dialog, response): - if response != Gtk.ResponseType.ACCEPT: - return - - self.window.show_toast(_("Importing backup…")) - RunAsync( - task_func=BackupManager.import_backup, - callback=self.__finish, - scope="config", - path=dialog.get_file().get_path(), - ) - - dialog = Gtk.FileChooserNative.new( - title=_("Select a Configuration File"), - action=Gtk.FileChooserAction.OPEN, - parent=self.window, - accept_label=_("Import"), - ) - - add_yaml_filters(dialog) - add_all_filters(dialog) - dialog.set_modal(True) - dialog.connect("response", set_path) - dialog.show() - - def go_back(self, *_args): - self.window.main_leaf.navigate(Adw.NavigationDirection.BACK) diff --git a/bottles/frontend/main.py b/bottles/frontend/main.py index 19796683295..a2cdb82bf63 100644 --- a/bottles/frontend/main.py +++ b/bottles/frontend/main.py @@ -92,7 +92,6 @@ def __init__(self): ) self.__create_action("quit", self.__quit, ["q", "w"]) self.__create_action("about", self.__show_about_dialog) - self.__create_action("import", self.__show_importer_view, ["i"]) self.__create_action("preferences", self.__show_preferences, ["comma"]) self.__create_action("help", self.__help, ["F1"]) self.__create_action("new", self.__new_bottle, ["n"]) @@ -296,9 +295,6 @@ def __show_preferences(self, *args): def __new_bottle(self, *args): self.win.show_add_view() - def __show_importer_view(self, widget=False, *args): - self.win.main_leaf.set_visible_child(self.win.page_importer) - def __show_about_dialog(self, *_args): developers = [ "Mirko Brombin https://github.com/mirkobrombin", diff --git a/bottles/frontend/meson.build b/bottles/frontend/meson.build index 780f1bff3f4..7513af2d715 100644 --- a/bottles/frontend/meson.build +++ b/bottles/frontend/meson.build @@ -37,8 +37,6 @@ blueprints = custom_target('blueprints', 'dll-override-entry.blp', 'drive-entry.blp', 'env-var-entry.blp', - 'importer-row.blp', - 'importer-view.blp', 'library-entry.blp', 'library-view.blp', 'bottle-row.blp', @@ -93,7 +91,6 @@ bottles_sources = [ 'library_view.py', 'bottle_details_view.py', 'preferences.py', - 'importer_view.py', 'loading_view.py', 'bottle_details_page.py', 'details_dependencies_view.py', @@ -101,7 +98,6 @@ bottles_sources = [ 'details_task_manager_view.py', 'dependency_entry_row.py', 'executable.py', - 'importer_row.py', 'program_row.py', 'component_entry_row.py', 'library_entry.py', diff --git a/bottles/frontend/window.blp b/bottles/frontend/window.blp index cc3bf7155f2..3c517936a91 100644 --- a/bottles/frontend/window.blp +++ b/bottles/frontend/window.blp @@ -75,13 +75,6 @@ template $BottlesWindow: Adw.ApplicationWindow { } menu primary_menu { - section { - item { - label: _("_Import…"); - action: "app.import"; - } - } - section { item { label: _("_Preferences"); diff --git a/bottles/frontend/window.py b/bottles/frontend/window.py index 6156bc122b2..37f1a3f6f5e 100644 --- a/bottles/frontend/window.py +++ b/bottles/frontend/window.py @@ -34,7 +34,6 @@ from bottles.frontend.params import APP_ID, BASE_ID, PROFILE from bottles.frontend.gtk import GtkUtils from bottles.frontend.bottle_details_view import BottleDetailsView -from bottles.frontend.importer_view import ImporterView from bottles.frontend.library_view import LibraryView from bottles.frontend.bottles_list_view import BottlesListView from bottles.frontend.loading_view import LoadingView @@ -204,14 +203,11 @@ def set_manager(result: Manager, error=None): # Pages self.page_details = BottleDetailsView(self) self.page_list = BottlesListView(self) - self.page_importer = ImporterView(self) self.page_library = LibraryView(self) self.main_leaf.append(self.page_details) - self.main_leaf.append(self.page_importer) self.main_leaf.get_page(self.page_details).set_navigatable(False) - self.main_leaf.get_page(self.page_importer).set_navigatable(False) self.stack_main.add_titled( child=self.page_list, name="page_list", title=_("Bottles") @@ -294,9 +290,6 @@ def show_add_view(self, widget=False): def show_list_view(self, widget=False): self.stack_main.set_visible_child_name("page_list") - def show_importer_view(self, widget=False): - self.main_leaf.set_visible_child(self.page_importer) - def show_prefs_view(self, widget=False, view=0): preferences_window = PreferencesWindow(self) preferences_window.present() From b8bd571cc4ddd703b5993d6ec25ee500a4d1f772 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Sun, 2 Feb 2025 22:27:10 -0500 Subject: [PATCH 117/146] backend: Remove ImporterManager --- bottles/backend/managers/importer.py | 127 --------------------------- bottles/backend/managers/manager.py | 5 -- bottles/backend/managers/meson.build | 1 - 3 files changed, 133 deletions(-) delete mode 100644 bottles/backend/managers/importer.py diff --git a/bottles/backend/managers/importer.py b/bottles/backend/managers/importer.py deleted file mode 100644 index 14f4c4e30c0..00000000000 --- a/bottles/backend/managers/importer.py +++ /dev/null @@ -1,127 +0,0 @@ -# importer.py -# -# Copyright 2022 brombinmirko -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, in version 3 of the License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# - -import os - -from bottles.backend.models.config import BottleConfig -import subprocess -from glob import glob -from datetime import datetime - -import logging -from bottles.backend.globals import TrdyPaths, Paths -from bottles.backend.models.result import Result - - -class ImportManager: - def __init__(self, manager): - self.manager = manager - - @staticmethod - def search_wineprefixes() -> Result: - """Look and return all 3rd party available wine prefixes""" - importer_wineprefixes = [] - - # search wine prefixes in external managers paths - wine_standard = glob(TrdyPaths.wine) - lutris_results = glob(f"{TrdyPaths.lutris}/*/") - playonlinux_results = glob(f"{TrdyPaths.playonlinux}/*/") - bottlesv1_results = glob(f"{TrdyPaths.bottlesv1}/*/") - - results = ( - wine_standard + lutris_results + playonlinux_results + bottlesv1_results - ) - - # count results - is_wine = len(wine_standard) - is_lutris = len(lutris_results) - is_playonlinux = len(playonlinux_results) - i = 1 - - for wineprefix in results: - wineprefix_name = wineprefix.split("/")[-2] - - # identify manager by index - if i <= is_wine: - wineprefix_manager = "Legacy Wine" - elif i <= is_wine + is_lutris: - wineprefix_manager = "Lutris" - elif i <= is_wine + is_lutris + is_playonlinux: - wineprefix_manager = "PlayOnLinux" - else: - wineprefix_manager = "Bottles v1" - - # check the drive_c path exists - if os.path.isdir(os.path.join(wineprefix, "drive_c")): - wineprefix_lock = os.path.isfile( - os.path.join(wineprefix, "bottle.lock") - ) - importer_wineprefixes.append( - { - "Name": wineprefix_name, - "Manager": wineprefix_manager, - "Path": wineprefix, - "Lock": wineprefix_lock, - } - ) - i += 1 - - logging.info(f"Found {len(importer_wineprefixes)} wine prefixes…") - - return Result(status=True, data={"wineprefixes": importer_wineprefixes}) - - def import_wineprefix(self, wineprefix: dict) -> Result: - """Import wineprefix from external manager and convert in a bottle""" - logging.info(f"Importing wineprefix {wineprefix['Name']} as bottle…") - - # prepare bottle path for the wine prefix - bottle_path = f"Imported_{wineprefix.get('Name')}" - bottle_complete_path = os.path.join(Paths.bottles, bottle_path) - - try: - os.makedirs(bottle_complete_path, exist_ok=False) - except (FileExistsError, OSError): - logging.error(f"Error creating bottle directory for {wineprefix['Name']}") - return Result(False) - - # create lockfile in source path - logging.info(f"Creating lock file in {wineprefix['Path']}…") - open(f'{wineprefix.get("Path")}/bottle.lock', "a").close() - - # copy wineprefix files in the new bottle - command = f"cp -a {wineprefix.get('Path')}/* {bottle_complete_path}/" - subprocess.Popen(command, shell=True).communicate() - - # create bottle config - new_config = BottleConfig() - new_config.Name = wineprefix["Name"] - new_config.Runner = self.manager.get_latest_runner() - new_config.Path = bottle_path - new_config.Environment = "Custom" - new_config.Creation_Date = str(datetime.now()) - new_config.Update_Date = str(datetime.now()) - - # save config - saved = new_config.dump(os.path.join(bottle_complete_path, "bottle.yml")) - if not saved.status: - return Result(False) - - # update bottles view - self.manager.update_bottles(silent=True) - - logging.info(f"Wine prefix {wineprefix['Name']} imported as bottle.") - return Result(True) diff --git a/bottles/backend/managers/manager.py b/bottles/backend/managers/manager.py index 053cfac9067..6e2656cdb0f 100644 --- a/bottles/backend/managers/manager.py +++ b/bottles/backend/managers/manager.py @@ -37,7 +37,6 @@ from bottles.backend.globals import Paths import logging from bottles.backend.managers.epicgamesstore import EpicGamesStoreManager -from bottles.backend.managers.importer import ImportManager from bottles.backend.managers.library import LibraryManager from bottles.backend.managers.template import TemplateManager from bottles.backend.managers.ubisoftconnect import UbisoftConnectManager @@ -106,10 +105,6 @@ def __init__( self.settings = g_settings or GSettingsStub _offline = False - # sub-managers - self.import_manager = ImportManager(self) - times["ImportManager"] = time.time() - times.update(self.checks(install_latest=False, first_run=True).data) if "BOOT_TIME" in os.environ: diff --git a/bottles/backend/managers/meson.build b/bottles/backend/managers/meson.build index 355b0bb2206..8d3afa790a5 100644 --- a/bottles/backend/managers/meson.build +++ b/bottles/backend/managers/meson.build @@ -6,7 +6,6 @@ bottles_sources = [ 'backup.py', 'library.py', 'manager.py', - 'importer.py', 'conf.py', 'template.py', 'sandbox.py', From 0b505b33820d33fd30ac7107830bae12d923fc4c Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Sun, 2 Feb 2025 22:34:13 -0500 Subject: [PATCH 118/146] frontend: Remove EpicGamesStoreManager --- bottles/frontend/preferences.blp | 10 ---------- bottles/frontend/preferences.py | 7 ------- 2 files changed, 17 deletions(-) diff --git a/bottles/frontend/preferences.blp b/bottles/frontend/preferences.blp index 53394c9630a..a62cbd3302d 100644 --- a/bottles/frontend/preferences.blp +++ b/bottles/frontend/preferences.blp @@ -94,16 +94,6 @@ template $PreferencesWindow: Adw.PreferencesWindow { } } - Adw.ActionRow { - title: _("List Epic Games in Programs List"); - subtitle: _("Requires Epic Games Store installed in the bottle."); - activatable-widget: switch_epic_games; - - Switch switch_epic_games { - valign: center; - } - } - Adw.ActionRow { title: _("List Ubisoft Games in Programs List"); subtitle: _("Requires Ubisoft Connect installed in the bottle."); diff --git a/bottles/frontend/preferences.py b/bottles/frontend/preferences.py index af60bfd6c24..d8d9f0653ba 100644 --- a/bottles/frontend/preferences.py +++ b/bottles/frontend/preferences.py @@ -53,7 +53,6 @@ class PreferencesWindow(Adw.PreferencesWindow): switch_auto_close = Gtk.Template.Child() switch_update_date = Gtk.Template.Child() switch_steam_programs = Gtk.Template.Child() - switch_epic_games = Gtk.Template.Child() switch_ubisoft_connect = Gtk.Template.Child() list_runners = Gtk.Template.Child() list_dxvk = Gtk.Template.Child() @@ -132,12 +131,6 @@ def __init__(self, window, **kwargs): "active", Gio.SettingsBindFlags.DEFAULT, ) - self.settings.bind( - "epic-games", - self.switch_epic_games, - "active", - Gio.SettingsBindFlags.DEFAULT, - ) self.settings.bind( "ubisoft-connect", self.switch_ubisoft_connect, From 1216c995f12ac1acf8cb7927bf28f61f6a4efb63 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Sun, 2 Feb 2025 22:35:25 -0500 Subject: [PATCH 119/146] backend: Remove EpicGamesStoreManager --- bottles/backend/managers/epicgamesstore.py | 86 ---------------------- bottles/backend/managers/manager.py | 9 --- bottles/backend/managers/meson.build | 1 - data/com.usebottles.bottles.gschema.xml | 5 -- 4 files changed, 101 deletions(-) delete mode 100644 bottles/backend/managers/epicgamesstore.py diff --git a/bottles/backend/managers/epicgamesstore.py b/bottles/backend/managers/epicgamesstore.py deleted file mode 100644 index 127fe616f95..00000000000 --- a/bottles/backend/managers/epicgamesstore.py +++ /dev/null @@ -1,86 +0,0 @@ -# epicgamesstore.py -# -# Copyright 2022 brombinmirko -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, in version 3 of the License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# - -import os -import uuid - -from bottles.backend.models.config import BottleConfig -from bottles.backend.utils import json -from bottles.backend.utils.manager import ManagerUtils - - -class EpicGamesStoreManager: - @staticmethod - def find_dat_path(config: BottleConfig) -> str | None: - """ - Finds the Epic Games dat file path. - """ - paths = [ - os.path.join( - ManagerUtils.get_bottle_path(config), - "drive_c/ProgramData/Epic/UnrealEngineLauncher/LauncherInstalled.dat", - ) - ] - - for path in paths: - if os.path.exists(path): - return path - return None - - @staticmethod - def is_epic_supported(config: BottleConfig) -> bool: - """ - Checks if Epic Games is supported. - """ - return EpicGamesStoreManager.find_dat_path(config) is not None - - @staticmethod - def get_installed_games(config: BottleConfig) -> list: - """ - Gets the games. - """ - games = [] - dat_path = EpicGamesStoreManager.find_dat_path(config) - - if dat_path is None: - return [] - - with open(dat_path) as dat: - data = json.load(dat) - - for game in data["InstallationList"]: - _uri = f"-com.epicgames.launcher://apps/{game['AppName']}?action=launch&silent=true" - _args = f"-opengl -SkipBuildPatchPrereq {_uri}" - _name = game["InstallLocation"].split("\\")[-1] - _path = ( - "C:\\Program Files (x86)\\Epic Games\\Launcher\\Portal\\Binaries\\Win32\\" - "EpicGamesLauncher.exe" - ) - _executable = _path.split("\\")[-1] - _folder = ManagerUtils.get_exe_parent_dir(config, _path) - games.append( - { - "executable": _path, - "arguments": _args, - "name": _name, - "path": _path, - "folder": _folder, - "icon": "com.usebottles.bottles-program", - "id": str(uuid.uuid4()), - } - ) - return games diff --git a/bottles/backend/managers/manager.py b/bottles/backend/managers/manager.py index 6e2656cdb0f..60ffa1e4407 100644 --- a/bottles/backend/managers/manager.py +++ b/bottles/backend/managers/manager.py @@ -36,7 +36,6 @@ from bottles.backend.dlls.vkd3d import VKD3DComponent from bottles.backend.globals import Paths import logging -from bottles.backend.managers.epicgamesstore import EpicGamesStoreManager from bottles.backend.managers.library import LibraryManager from bottles.backend.managers.template import TemplateManager from bottles.backend.managers.ubisoftconnect import UbisoftConnectManager @@ -563,14 +562,6 @@ def get_programs(self, config: BottleConfig) -> list[dict]: ) found.append(executable_name) - if self.settings.get_boolean( - "epic-games" - ) and EpicGamesStoreManager.is_epic_supported(config): - programs_names = [p.get("name", "") for p in installed_programs] - for app in EpicGamesStoreManager.get_installed_games(config): - if app["name"] not in programs_names: - installed_programs.append(app) - if self.settings.get_boolean( "ubisoft-connect" ) and UbisoftConnectManager.is_uconnect_supported(config): diff --git a/bottles/backend/managers/meson.build b/bottles/backend/managers/meson.build index 8d3afa790a5..cceb138a3bb 100644 --- a/bottles/backend/managers/meson.build +++ b/bottles/backend/managers/meson.build @@ -9,7 +9,6 @@ bottles_sources = [ 'conf.py', 'template.py', 'sandbox.py', - 'epicgamesstore.py', 'ubisoftconnect.py', 'origin.py', 'steamgriddb.py', diff --git a/data/com.usebottles.bottles.gschema.xml b/data/com.usebottles.bottles.gschema.xml index f8167f30868..83c69694b3a 100644 --- a/data/com.usebottles.bottles.gschema.xml +++ b/data/com.usebottles.bottles.gschema.xml @@ -26,11 +26,6 @@ Steam apps listing Toggle steam apps listing. - - true - Epic Games listing - Toggle epic games listing. - true Ubisoft Connect listing From b0f9d39d2bcff7d9f535f146455e0739685ed432 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Sun, 2 Feb 2025 22:39:24 -0500 Subject: [PATCH 120/146] frontend: Remove UbisoftConnectManager --- bottles/frontend/preferences.blp | 10 ---------- bottles/frontend/preferences.py | 7 ------- 2 files changed, 17 deletions(-) diff --git a/bottles/frontend/preferences.blp b/bottles/frontend/preferences.blp index a62cbd3302d..c90ca549d61 100644 --- a/bottles/frontend/preferences.blp +++ b/bottles/frontend/preferences.blp @@ -93,16 +93,6 @@ template $PreferencesWindow: Adw.PreferencesWindow { valign: center; } } - - Adw.ActionRow { - title: _("List Ubisoft Games in Programs List"); - subtitle: _("Requires Ubisoft Connect installed in the bottle."); - activatable-widget: switch_ubisoft_connect; - - Switch switch_ubisoft_connect { - valign: center; - } - } } Adw.PreferencesGroup { diff --git a/bottles/frontend/preferences.py b/bottles/frontend/preferences.py index d8d9f0653ba..64a1a288504 100644 --- a/bottles/frontend/preferences.py +++ b/bottles/frontend/preferences.py @@ -53,7 +53,6 @@ class PreferencesWindow(Adw.PreferencesWindow): switch_auto_close = Gtk.Template.Child() switch_update_date = Gtk.Template.Child() switch_steam_programs = Gtk.Template.Child() - switch_ubisoft_connect = Gtk.Template.Child() list_runners = Gtk.Template.Child() list_dxvk = Gtk.Template.Child() list_vkd3d = Gtk.Template.Child() @@ -131,12 +130,6 @@ def __init__(self, window, **kwargs): "active", Gio.SettingsBindFlags.DEFAULT, ) - self.settings.bind( - "ubisoft-connect", - self.switch_ubisoft_connect, - "active", - Gio.SettingsBindFlags.DEFAULT, - ) # setup loading screens self.installers_stack.set_visible_child_name("installers_loading") From a43903a20a8a2396f5e26d9d7c701642928761d1 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Sun, 2 Feb 2025 22:40:49 -0500 Subject: [PATCH 121/146] backend: Remove UbisoftConnectManager --- bottles/backend/managers/manager.py | 9 -- bottles/backend/managers/meson.build | 1 - bottles/backend/managers/ubisoftconnect.py | 131 --------------------- data/com.usebottles.bottles.gschema.xml | 5 - 4 files changed, 146 deletions(-) delete mode 100644 bottles/backend/managers/ubisoftconnect.py diff --git a/bottles/backend/managers/manager.py b/bottles/backend/managers/manager.py index 60ffa1e4407..26241bfe055 100644 --- a/bottles/backend/managers/manager.py +++ b/bottles/backend/managers/manager.py @@ -38,7 +38,6 @@ import logging from bottles.backend.managers.library import LibraryManager from bottles.backend.managers.template import TemplateManager -from bottles.backend.managers.ubisoftconnect import UbisoftConnectManager from bottles.backend.models.config import BottleConfig from bottles.backend.models.result import Result from bottles.backend.models.samples import Samples @@ -562,14 +561,6 @@ def get_programs(self, config: BottleConfig) -> list[dict]: ) found.append(executable_name) - if self.settings.get_boolean( - "ubisoft-connect" - ) and UbisoftConnectManager.is_uconnect_supported(config): - programs_names = [p.get("name", "") for p in installed_programs] - for app in UbisoftConnectManager.get_installed_games(config): - if app["name"] not in programs_names: - installed_programs.append(app) - return installed_programs def check_bottles(self, silent: bool = False): diff --git a/bottles/backend/managers/meson.build b/bottles/backend/managers/meson.build index cceb138a3bb..154c88d7169 100644 --- a/bottles/backend/managers/meson.build +++ b/bottles/backend/managers/meson.build @@ -9,7 +9,6 @@ bottles_sources = [ 'conf.py', 'template.py', 'sandbox.py', - 'ubisoftconnect.py', 'origin.py', 'steamgriddb.py', 'thumbnail.py' diff --git a/bottles/backend/managers/ubisoftconnect.py b/bottles/backend/managers/ubisoftconnect.py deleted file mode 100644 index e56633e4094..00000000000 --- a/bottles/backend/managers/ubisoftconnect.py +++ /dev/null @@ -1,131 +0,0 @@ -# ubisoftconnect.py -# -# Copyright 2022 brombinmirko -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, in version 3 of the License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# - -import os -import uuid - -from bottles.backend.models.config import BottleConfig -from bottles.backend.utils.manager import ManagerUtils - - -class UbisoftConnectManager: - @staticmethod - def find_conf_path(config: BottleConfig) -> str | None: - """ - Finds the Ubisoft Connect configurations file path. - """ - paths = [ - os.path.join( - ManagerUtils.get_bottle_path(config), - "drive_c/Program Files (x86)/Ubisoft/Ubisoft Game Launcher/cache/configuration/configurations", - ) - ] - - for path in paths: - if os.path.exists(path): - return path - return None - - @staticmethod - def is_uconnect_supported(config: BottleConfig) -> bool: - """ - Checks if Ubisoft Connect is supported. - """ - return UbisoftConnectManager.find_conf_path(config) is not None - - # noinspection PyTypeChecker - @staticmethod - def get_installed_games(config: BottleConfig) -> list: - """ - Gets the games. - """ - found = {} - games = [] - key: str | None = None - appid: str | None = None - thumb: str | None = None - reg_key = ( - "register: HKEY_LOCAL_MACHINE\\SOFTWARE\\Ubisoft\\Launcher\\Installs\\" - ) - conf_path = UbisoftConnectManager.find_conf_path(config) - games_path = os.path.join( - ManagerUtils.get_bottle_path(config), - "drive_c/Program Files (x86)/Ubisoft/Ubisoft Game Launcher/games", - ) - - if conf_path is None: - return [] - - with open(conf_path, encoding="iso-8859-15") as c: - for r in c.readlines(): - r = r.strip() - - if r.startswith("name:"): - _key = r.replace("name:", "").strip() - if _key != "" and _key not in found.keys(): - key = _key - found[key] = {"name": None, "appid": None, "thumb_image": None} - - elif key and r.startswith("- shortcut_name:"): - _name = r.replace("- shortcut_name:", "").strip() - if _name != "": - name = _name - found[key]["name"] = name - - elif ( - key and found[key]["name"] is None and r.startswith("display_name:") - ): - name = r.replace("display_name:", "").strip() - found[key]["name"] = name - - elif key and r.startswith("thumb_image:"): - thumb = r.replace("thumb_image:", "").strip() - found[key]["thumb_image"] = thumb - - elif key and r.startswith(reg_key): - appid = r.replace(reg_key, "").replace("\\InstallDir", "").strip() - found[key]["appid"] = appid - - if None not in [key, appid, thumb]: - key, name, appid, thumb = None, None, None, None - - for k, v in found.items(): - if v["name"] is None or not os.path.exists( - os.path.join(games_path, v["name"]) - ): - continue - - _args = f"uplay://launch/{v['appid']}/0" - _path = "C:\\Program Files (x86)\\Ubisoft\\Ubisoft Game Launcher\\UbisoftConnect.exe" - _executable = _path.split("\\")[-1] - _folder = ManagerUtils.get_exe_parent_dir(config, _path) - _thumb = ( - "" if v["thumb_image"] is None else f"ubisoft:{v['thumb_image']}" - ) - games.append( - { - "executable": _path, - "arguments": _args, - "name": v["name"], - "thumb": _thumb, - "path": _path, - "folder": _folder, - "icon": "com.usebottles.bottles-program", - "id": str(uuid.uuid4()), - } - ) - return games diff --git a/data/com.usebottles.bottles.gschema.xml b/data/com.usebottles.bottles.gschema.xml index 83c69694b3a..687a06a10d1 100644 --- a/data/com.usebottles.bottles.gschema.xml +++ b/data/com.usebottles.bottles.gschema.xml @@ -26,11 +26,6 @@ Steam apps listing Toggle steam apps listing. - - true - Ubisoft Connect listing - Toggle ubisoft connect listing. - 880 Window width From 69b6b1bdeb78f5925e9f9c20446368a68a5a0b6a Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Sun, 2 Feb 2025 22:54:34 -0500 Subject: [PATCH 122/146] backend: Remove OriginManager --- bottles/backend/managers/meson.build | 1 - bottles/backend/managers/origin.py | 55 ---------------------------- 2 files changed, 56 deletions(-) delete mode 100644 bottles/backend/managers/origin.py diff --git a/bottles/backend/managers/meson.build b/bottles/backend/managers/meson.build index 154c88d7169..650c2d94497 100644 --- a/bottles/backend/managers/meson.build +++ b/bottles/backend/managers/meson.build @@ -9,7 +9,6 @@ bottles_sources = [ 'conf.py', 'template.py', 'sandbox.py', - 'origin.py', 'steamgriddb.py', 'thumbnail.py' ] diff --git a/bottles/backend/managers/origin.py b/bottles/backend/managers/origin.py deleted file mode 100644 index 1e50b490519..00000000000 --- a/bottles/backend/managers/origin.py +++ /dev/null @@ -1,55 +0,0 @@ -# origin.py -# -# Copyright 2022 brombinmirko -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, in version 3 of the License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# - -import os - -from bottles.backend.models.config import BottleConfig -from bottles.backend.utils.manager import ManagerUtils - - -class OriginManager: - @staticmethod - def find_manifests_path(config: BottleConfig) -> str | None: - """ - Finds the Origin manifests path. - """ - paths = [ - os.path.join( - ManagerUtils.get_bottle_path(config), - "drive_c/ProgramData/Origin/LocalContent", - ) - ] - - for path in paths: - if os.path.exists(path): - return path - return None - - @staticmethod - def is_origin_supported(config: BottleConfig) -> bool: - """ - Checks if Origin is supported. - """ - return OriginManager.find_manifests_path(config) is not None - - @staticmethod - def get_installed_games(config: BottleConfig) -> list: - """ - Gets the games. - """ - games = [] - return games From 71d4e05cfa7980fa149f372da5ec01341b051b4b Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Tue, 4 Feb 2025 09:27:53 -0500 Subject: [PATCH 123/146] frontend: Remove BackupManager --- bottles/frontend/bottle-details-page.blp | 14 ---- bottles/frontend/bottle_details_page.py | 77 ------------------ bottles/frontend/bottles.gresource.xml | 1 - bottles/frontend/duplicate-dialog.blp | 99 ------------------------ bottles/frontend/duplicate_dialog.py | 92 ---------------------- bottles/frontend/meson.build | 2 - 6 files changed, 285 deletions(-) delete mode 100644 bottles/frontend/duplicate-dialog.blp delete mode 100644 bottles/frontend/duplicate_dialog.py diff --git a/bottles/frontend/bottle-details-page.blp b/bottles/frontend/bottle-details-page.blp index 29973e9377e..73a263201e3 100644 --- a/bottles/frontend/bottle-details-page.blp +++ b/bottles/frontend/bottle-details-page.blp @@ -24,20 +24,6 @@ Popover pop_context { text: _("Browse Files…"); } - $GtkModelButton btn_duplicate { - text: _("Duplicate Bottle…"); - } - - $GtkModelButton btn_backup_full { - tooltip-text: _("This is the complete archive of your bottle, including personal files."); - text: _("Full Backup…"); - } - - $GtkModelButton btn_backup_config { - tooltip-text: _("This is just the bottle configuration, it\'s perfect if you want to create a new one but without personal files."); - text: _("Export Configuration…"); - } - Separator {} $GtkModelButton btn_toggle_removed { diff --git a/bottles/frontend/bottle_details_page.py b/bottles/frontend/bottle_details_page.py index 83553fe0c96..2a6fdeec88f 100644 --- a/bottles/frontend/bottle_details_page.py +++ b/bottles/frontend/bottle_details_page.py @@ -21,7 +21,6 @@ from gi.repository import Gtk, Gio, Adw, Gdk, GLib, Xdp -from bottles.backend.managers.backup import BackupManager from bottles.backend.models.config import BottleConfig from bottles.backend.utils.manager import ManagerUtils from bottles.backend.utils.terminal import TerminalUtils @@ -41,7 +40,6 @@ from bottles.frontend.filters import add_executable_filters, add_all_filters from bottles.frontend.gtk import GtkUtils from bottles.frontend.program_row import ProgramRow -from bottles.frontend.duplicate_dialog import DuplicateDialog @Gtk.Template(resource_path="/com/usebottles/bottles/bottle-details-page.ui") @@ -78,9 +76,6 @@ class BottleDetailsPage(Adw.PreferencesPage): btn_nv_forcestop = Gtk.Template.Child() btn_update = Gtk.Template.Child() btn_toggle_removed = Gtk.Template.Child() - btn_backup_config = Gtk.Template.Child() - btn_backup_full = Gtk.Template.Child() - btn_duplicate = Gtk.Template.Child() btn_delete = Gtk.Template.Child() btn_flatpak_doc = Gtk.Template.Child() label_name = Gtk.Template.Child() @@ -138,9 +133,6 @@ def __init__(self, details, config, **kwargs): self.btn_nv_forcestop.connect("clicked", self.wineboot, -2) self.btn_update.connect("clicked", self.__scan_programs) self.btn_toggle_removed.connect("clicked", self.__toggle_removed) - self.btn_backup_config.connect("clicked", self.__backup, "config") - self.btn_backup_full.connect("clicked", self.__backup, "full") - self.btn_duplicate.connect("clicked", self.__duplicate) self.btn_flatpak_doc.connect( "clicked", open_doc_url, "flatpak/black-screen-or-silent-crash" ) @@ -217,8 +209,6 @@ def set_config(self, config: BottleConfig): self.grid_versioning.set_visible(self.config.Versioning) self.label_state.set_text(str(self.config.State)) - self.__set_steam_rules() - if ( config.Runner not in self.manager.runners_available and not self.config.Environment == "Steam" @@ -435,66 +425,6 @@ def callback(a, b): else: show_chooser() - def __backup(self, widget, backup_type): - """ - This function pop up the file chooser where the user - can select the path where to export the bottle backup. - Use the backup_type param to export config or full. - """ - if backup_type == "config": - title = _("Select the location where to save the backup config") - hint = f"backup_{self.config.Path}.yml" - accept_label = _("Export") - else: - title = _("Select the location where to save the backup archive") - hint = f"backup_{self.config.Path}.tar.gz" - accept_label = _("Backup") - - @GtkUtils.run_in_main_loop - def finish(result, error=False): - if result.ok: - self.window.show_toast( - _('Backup created for "{0}"').format(self.config.Name) - ) - else: - self.window.show_toast( - _('Backup failed for "{0}"').format(self.config.Name) - ) - - def set_path(_dialog, response): - if response != Gtk.ResponseType.ACCEPT: - return - - path = dialog.get_file().get_path() - - RunAsync( - task_func=BackupManager.export_backup, - callback=finish, - config=self.config, - scope=backup_type, - path=path, - ) - - dialog = Gtk.FileChooserNative.new( - title=title, - action=Gtk.FileChooserAction.SAVE, - parent=self.window, - accept_label=accept_label, - ) - - dialog.set_modal(True) - dialog.connect("response", set_path) - dialog.set_current_name(hint) - dialog.show() - - def __duplicate(self, widget): - """ - This function pop up the duplicate dialog, so the user can - choose the new bottle name and perform duplication. - """ - new_window = DuplicateDialog(self) - new_window.present() - def __confirm_delete(self, widget): """ This function pop up to delete confirm dialog. If user confirm @@ -622,10 +552,3 @@ def handle_response(_widget, response_id): dialog.set_response_appearance("ok", Adw.ResponseAppearance.DESTRUCTIVE) dialog.connect("response", handle_response) dialog.present() - - def __set_steam_rules(self): - status = False if self.config.Environment == "Steam" else True - - for w in [self.btn_delete, self.btn_backup_full, self.btn_duplicate]: - w.set_visible(status) - w.set_sensitive(status) diff --git a/bottles/frontend/bottles.gresource.xml b/bottles/frontend/bottles.gresource.xml index 62dd7b1e21f..2ec0ed7b5ec 100644 --- a/bottles/frontend/bottles.gresource.xml +++ b/bottles/frontend/bottles.gresource.xml @@ -30,7 +30,6 @@ dll-overrides-dialog.ui environment-variables-dialog.ui crash-report-dialog.ui - duplicate-dialog.ui rename-program-dialog.ui gamescope-dialog.ui vkbasalt-dialog.ui diff --git a/bottles/frontend/duplicate-dialog.blp b/bottles/frontend/duplicate-dialog.blp deleted file mode 100644 index 024ed9bebf4..00000000000 --- a/bottles/frontend/duplicate-dialog.blp +++ /dev/null @@ -1,99 +0,0 @@ -using Gtk 4.0; -using Adw 1; - -template $DuplicateDialog: Adw.Window { - modal: true; - default-width: 400; - default-height: 400; - destroy-with-parent: true; - - Box { - orientation: vertical; - - Adw.HeaderBar { - show-end-title-buttons: false; - - title-widget: Adw.WindowTitle { - title: _("Duplicate Bottle"); - }; - - Button btn_cancel { - label: _("_Cancel"); - use-underline: true; - action-name: "window.close"; - } - - ShortcutController { - scope: managed; - - Shortcut { - trigger: "Escape"; - action: "action(window.close)"; - } - } - - [end] - Button btn_duplicate { - label: _("Duplicate"); - - styles [ - "suggested-action", - ] - } - } - - Stack stack_switcher { - Adw.PreferencesPage page_name { - Adw.PreferencesGroup { - description: _("Enter a name for the duplicate of the Bottle."); - - Adw.EntryRow entry_name { - title: _("Name"); - } - } - } - - StackPage { - name: "page_duplicating"; - - child: Box page_duplicating { - margin-top: 24; - margin-bottom: 24; - orientation: vertical; - - Label { - halign: center; - margin-top: 12; - margin-bottom: 12; - label: _("Duplicating…"); - - styles [ - "title-1", - ] - } - - Label { - margin-bottom: 6; - label: _("This could take a while."); - } - - ProgressBar progressbar { - width-request: 300; - halign: center; - margin-top: 24; - margin-bottom: 12; - } - }; - } - - StackPage { - name: "page_duplicated"; - - child: Adw.StatusPage page_duplicated { - icon-name: "object-select-symbolic"; - title: _("Bottle Duplicated"); - }; - } - } - } -} diff --git a/bottles/frontend/duplicate_dialog.py b/bottles/frontend/duplicate_dialog.py deleted file mode 100644 index a3b839430de..00000000000 --- a/bottles/frontend/duplicate_dialog.py +++ /dev/null @@ -1,92 +0,0 @@ -# duplicate_dialog.py -# -# Copyright 2025 The Bottles Contributors -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, in version 3 of the License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# - -import time - -from gi.repository import Gtk, Adw - -from bottles.backend.managers.backup import BackupManager -from bottles.backend.utils.threading import RunAsync -from bottles.frontend.gtk import GtkUtils - - -@Gtk.Template(resource_path="/com/usebottles/bottles/duplicate-dialog.ui") -class DuplicateDialog(Adw.Window): - __gtype_name__ = "DuplicateDialog" - - # region Widgets - entry_name = Gtk.Template.Child() - btn_cancel = Gtk.Template.Child() - btn_duplicate = Gtk.Template.Child() - stack_switcher = Gtk.Template.Child() - progressbar = Gtk.Template.Child() - - # endregion - - def __init__(self, parent, **kwargs): - super().__init__(**kwargs) - self.set_transient_for(parent.window) - - # common variables and references - self.parent = parent - self.config = parent.config - - self.entry_name.connect("changed", self.__check_entry_name) - - # connect signals - self.btn_duplicate.connect("clicked", self.__duplicate_bottle) - - def __check_entry_name(self, *_args): - is_duplicate = self.entry_name.get_text() in self.parent.manager.local_bottles - if is_duplicate: - self.entry_name.add_css_class("error") - self.btn_duplicate.set_sensitive(False) - else: - self.entry_name.remove_css_class("error") - self.btn_duplicate.set_sensitive(True) - - def __duplicate_bottle(self, widget): - """ - This function take the new bottle name from the entry - and create a new duplicate of the bottle. It also change the - stack_switcher page when the process is finished. - """ - self.stack_switcher.set_visible_child_name("page_duplicating") - self.btn_duplicate.set_visible(False) - self.btn_cancel.set_label("Close") - - RunAsync(self.pulse) - name = self.entry_name.get_text() - - RunAsync( - task_func=BackupManager.duplicate_bottle, - callback=self.finish, - config=self.config, - name=name, - ) - - @GtkUtils.run_in_main_loop - def finish(self, result, error=None): - # TODO: handle result.status == False - self.parent.manager.update_bottles() - self.stack_switcher.set_visible_child_name("page_duplicated") - - def pulse(self): - # This function update the progress bar every half second. - while True: - time.sleep(0.5) - self.progressbar.pulse() diff --git a/bottles/frontend/meson.build b/bottles/frontend/meson.build index 7513af2d715..fc4dee2e5bf 100644 --- a/bottles/frontend/meson.build +++ b/bottles/frontend/meson.build @@ -22,7 +22,6 @@ blueprints = custom_target('blueprints', 'dependencies-check-dialog.blp', 'dll-overrides-dialog.blp', 'drives-dialog.blp', - 'duplicate-dialog.blp', 'environment-variables-dialog.blp', 'gamescope-dialog.blp', 'launch-options-dialog.blp', @@ -103,7 +102,6 @@ bottles_sources = [ 'library_entry.py', 'crash_report_dialog.py', 'dll_overrides_dialog.py', - 'duplicate_dialog.py', 'environment_variables_dialog.py', 'generic.py', 'launch_options_dialog.py', From 29014452ea5bbd5156fc87797ee5e01de5c41675 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Tue, 4 Feb 2025 09:28:05 -0500 Subject: [PATCH 124/146] backend: Remove BackupManager --- bottles/backend/managers/backup.py | 220 --------------------------- bottles/backend/managers/meson.build | 1 - 2 files changed, 221 deletions(-) delete mode 100644 bottles/backend/managers/backup.py diff --git a/bottles/backend/managers/backup.py b/bottles/backend/managers/backup.py deleted file mode 100644 index 59223a9dee5..00000000000 --- a/bottles/backend/managers/backup.py +++ /dev/null @@ -1,220 +0,0 @@ -# backup.py -# -# Copyright 2022 brombinmirko -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, in version 3 of the License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# - -import os -import shutil -import tarfile -import pathvalidate -from gettext import gettext as _ - -from bottles.backend.globals import Paths -import logging -from bottles.backend.managers.manager import Manager -from bottles.backend.models.config import BottleConfig -from bottles.backend.models.result import Result -from bottles.backend.state import TaskManager, Task -from bottles.backend.utils import yaml -from bottles.backend.utils.manager import ManagerUtils - - -class BackupManager: - @staticmethod - def _validate_path(path: str) -> bool: - """Validate if the path is not None or empty.""" - if not path: - logging.error(_("No path specified")) - return False - return True - - @staticmethod - def _create_tarfile( - source_path: str, destination_path: str, exclude_filter=None - ) -> bool: - """Helper function to create a tar.gz file from a source path.""" - try: - with tarfile.open(destination_path, "w:gz") as tar: - os.chdir(os.path.dirname(source_path)) - tar.add(os.path.basename(source_path), filter=exclude_filter) - return True - except (FileNotFoundError, PermissionError, tarfile.TarError, ValueError) as e: - logging.error(f"Error creating backup: {e}") - return False - - @staticmethod - def _safe_extract_tarfile(tar_path: str, extract_path: str) -> bool: - """ - Safely extract a tar.gz file to avoid directory traversal - vulnerabilities. - """ - try: - with tarfile.open(tar_path, "r:gz") as tar: - # Validate each member - for member in tar.getmembers(): - member_path = os.path.abspath( - os.path.join(extract_path, member.name) - ) - if not member_path.startswith(os.path.abspath(extract_path)): - raise Exception("Detected path traversal attempt in tar file") - tar.extractall(path=extract_path) - return True - except (tarfile.TarError, Exception) as e: - logging.error(f"Error extracting backup: {e}") - return False - - @staticmethod - def export_backup(config: BottleConfig, scope: str, path: str) -> Result: - """ - Exports a bottle backup to the specified path. - Use the scope parameter to specify the backup type: config, full. - Config will only export the bottle configuration, full will export - the full bottle in tar.gz format. - """ - if not BackupManager._validate_path(path): - return Result(status=False) - - logging.info(f"Exporting {scope} backup for [{config.Name}] to [{path}]") - - if scope == "config": - backup_created = config.dump(path).status - else: - task_id = TaskManager.add(Task(title=_("Backup {0}").format(config.Name))) - bottle_path = ManagerUtils.get_bottle_path(config) - backup_created = BackupManager._create_tarfile( - bottle_path, path, exclude_filter=BackupManager.exclude_filter - ) - TaskManager.remove(task_id) - - if backup_created: - logging.info(f"Backup successfully saved to: {path}.") - return Result(status=True) - else: - logging.error("Failed to save backup.") - return Result(status=False) - - @staticmethod - def exclude_filter(tarinfo: tarfile.TarInfo) -> tarfile.TarInfo | None: - """ - Filter which excludes some unwanted files from the backup. - """ - if "dosdevices" in tarinfo.name: - return None - return tarinfo - - @staticmethod - def import_backup(scope: str, path: str) -> Result: - """ - Imports a backup from the specified path. - Use the scope parameter to specify the backup type: config, full. - Config will make a new bottle reproducing the configuration, full will - import the full bottle from a tar.gz file. - """ - if not BackupManager._validate_path(path): - return Result(status=False) - - logging.info(f"Importing backup from: {path}") - - if scope == "config": - return BackupManager._import_config_backup(path) - else: - return BackupManager._import_full_backup(path) - - @staticmethod - def _import_config_backup(path: str) -> Result: - task_id = TaskManager.add(Task(title=_("Importing config backup"))) - config_load = BottleConfig.load(path) - manager = Manager() - if ( - config_load.status - and config_load.data - and manager.create_bottle_from_config(config_load.data) - ): - TaskManager.remove(task_id) - logging.info("Config backup imported successfully.") - return Result(status=True) - else: - TaskManager.remove(task_id) - logging.error("Failed to import config backup.") - return Result(status=False) - - @staticmethod - def _import_full_backup(path: str) -> Result: - task_id = TaskManager.add(Task(title=_("Importing full backup"))) - if BackupManager._safe_extract_tarfile(path, Paths.bottles): - Manager().update_bottles() - TaskManager.remove(task_id) - logging.info("Full backup imported successfully.") - return Result(status=True) - else: - TaskManager.remove(task_id) - logging.error("Failed to import full backup.") - return Result(status=False) - - @staticmethod - def duplicate_bottle(config: BottleConfig, name: str) -> Result: - """ - Duplicates the bottle with the specified new name. - """ - logging.info(f"Duplicating bottle: {config.Name} as {name}") - - sanitized_name = pathvalidate.sanitize_filename(name, platform="universal") - source_path = ManagerUtils.get_bottle_path(config) - destination_path = os.path.join(Paths.bottles, sanitized_name) - - return BackupManager._duplicate_bottle_directory( - config, source_path, destination_path, name - ) - - @staticmethod - def _duplicate_bottle_directory( - config: BottleConfig, source_path: str, destination_path: str, new_name: str - ) -> Result: - try: - if not os.path.exists(destination_path): - os.makedirs(destination_path) - for item in [ - "drive_c", - "system.reg", - "user.reg", - "userdef.reg", - "bottle.yml", - ]: - source_item = os.path.join(source_path, item) - destination_item = os.path.join(destination_path, item) - if os.path.isdir(source_item): - shutil.copytree( - source_item, - destination_item, - ignore=shutil.ignore_patterns(".*"), - symlinks=True, - ) - elif os.path.isfile(source_item): - shutil.copy(source_item, destination_item) - - # Update the bottle configuration - config_path = os.path.join(destination_path, "bottle.yml") - with open(config_path) as config_file: - config_data = yaml.load(config_file) - config_data["Name"] = new_name - config_data["Path"] = destination_path - with open(config_path, "w") as config_file: - yaml.dump(config_data, config_file, indent=4) - - logging.info(f"Bottle duplicated successfully as {new_name}.") - return Result(status=True) - except (FileNotFoundError, PermissionError, OSError) as e: - logging.error(f"Error duplicating bottle: {e}") - return Result(status=False) diff --git a/bottles/backend/managers/meson.build b/bottles/backend/managers/meson.build index 650c2d94497..bbe7b30c0ed 100644 --- a/bottles/backend/managers/meson.build +++ b/bottles/backend/managers/meson.build @@ -3,7 +3,6 @@ managersdir = join_paths(pkgdatadir, 'bottles/backend/managers') bottles_sources = [ '__init__.py', - 'backup.py', 'library.py', 'manager.py', 'conf.py', From f748d6839d856954583525427ccf3cf3794f3386 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Tue, 4 Feb 2025 09:37:42 -0500 Subject: [PATCH 125/146] frontend: Remove LibraryManager --- bottles/frontend/bottles.gresource.xml | 2 - bottles/frontend/details_preferences_page.py | 16 +- bottles/frontend/library-entry.blp | 158 --------------- bottles/frontend/library-view.blp | 36 ---- bottles/frontend/library_entry.py | 194 ------------------- bottles/frontend/library_view.py | 90 --------- bottles/frontend/meson.build | 4 - bottles/frontend/program-row.blp | 4 - bottles/frontend/program_row.py | 60 +----- bottles/frontend/window.py | 8 - 10 files changed, 6 insertions(+), 566 deletions(-) delete mode 100644 bottles/frontend/library-entry.blp delete mode 100644 bottles/frontend/library-view.blp delete mode 100644 bottles/frontend/library_entry.py delete mode 100644 bottles/frontend/library_view.py diff --git a/bottles/frontend/bottles.gresource.xml b/bottles/frontend/bottles.gresource.xml index 2ec0ed7b5ec..d078011fbc6 100644 --- a/bottles/frontend/bottles.gresource.xml +++ b/bottles/frontend/bottles.gresource.xml @@ -17,7 +17,6 @@ env-var-entry.ui component-entry-row.ui drive-entry.ui - library-entry.ui local-resource-row.ui bottle-details-view.ui bottle-details-page.ui @@ -25,7 +24,6 @@ details-preferences-page.ui details-task-manager-view.ui preferences.ui - library-view.ui launch-options-dialog.ui dll-overrides-dialog.ui environment-variables-dialog.ui diff --git a/bottles/frontend/details_preferences_page.py b/bottles/frontend/details_preferences_page.py index ccd6b1f8957..d5b5e17c794 100644 --- a/bottles/frontend/details_preferences_page.py +++ b/bottles/frontend/details_preferences_page.py @@ -32,7 +32,6 @@ base_version, ) import logging -from bottles.backend.managers.library import LibraryManager from bottles.backend.models.config import BottleConfig from bottles.backend.models.enum import Arch from bottles.backend.models.result import Result @@ -274,20 +273,7 @@ def __save_name(self, *_args): return new_name = self.entry_name.get_text() - old_name = self.config.Name - - library_manager = LibraryManager() - entries = library_manager.get_library() - - for uuid, entry in entries.items(): - bottle = entry.get("bottle") - if bottle.get("name") == old_name: - logging.info(f"Updating library entry for {entry.get('name')}") - entries[uuid]["bottle"]["name"] = new_name - break - - library_manager.__library = entries - library_manager.save_library() + self.config.Name self.manager.update_config(config=self.config, key="Name", value=new_name) diff --git a/bottles/frontend/library-entry.blp b/bottles/frontend/library-entry.blp deleted file mode 100644 index 9d83e522032..00000000000 --- a/bottles/frontend/library-entry.blp +++ /dev/null @@ -1,158 +0,0 @@ -using Gtk 4.0; - -template $LibraryEntry: Box { - orientation: vertical; - width-request: 128; - height-request: 348; - overflow: hidden; - - Overlay overlay { - width-request: 226; - height-request: 348; - vexpand: true; - hexpand: true; - - [overlay] - Box { - orientation: vertical; - hexpand: true; - vexpand: true; - - Picture img_cover { - visible: false; - hexpand: true; - vexpand: true; - content-fit: cover; - } - - Label label_no_cover { - halign: center; - valign: center; - hexpand: true; - vexpand: true; - label: _("No Thumbnail"); - wrap: true; - wrap-mode: word_char; - - styles [ - "dim-label", - ] - } - } - - [overlay] - Revealer revealer_run { - reveal-child: false; - transition-type: crossfade; - valign: center; - - Box { - valign: center; - halign: center; - - Button btn_run { - valign: center; - halign: center; - label: _("Launch"); - - styles [ - "osd", - "pill", - ] - } - - [overlay] - Button btn_launch_steam { - valign: center; - halign: center; - visible: false; - label: _("Launch with Steam"); - - styles [ - "osd", - "pill", - ] - } - } - } - - [overlay] - Revealer revealer_details { - reveal-child: false; - transition-type: crossfade; - valign: end; - - Box { - spacing: 6; - halign: fill; - valign: end; - vexpand: true; - margin-bottom: 10; - margin-start: 10; - margin-end: 10; - - styles [ - "osd", - "toolbar", - "library-entry-details", - ] - - Box { - orientation: vertical; - hexpand: true; - valign: center; - - Label label_name { - halign: start; - label: _("Item name"); - max-width-chars: 20; - ellipsize: middle; - - styles [ - "title", - ] - } - - Label label_bottle { - halign: start; - label: _("Bottle name"); - max-width-chars: 20; - ellipsize: middle; - - styles [ - "caption", - ] - } - } - - [end] - Box { - Button btn_remove { - halign: center; - icon-name: "user-trash-symbolic"; - tooltip-text: _("Remove from Library"); - - styles [ - "flat" - ] - } - - Button btn_stop { - visible: false; - halign: center; - icon-name: "media-playback-stop-symbolic"; - tooltip-text: _("Stop"); - - styles [ - "flat" - ] - } - } - } - } - } - - styles [ - "card", - ] -} diff --git a/bottles/frontend/library-view.blp b/bottles/frontend/library-view.blp deleted file mode 100644 index 3e3289b8832..00000000000 --- a/bottles/frontend/library-view.blp +++ /dev/null @@ -1,36 +0,0 @@ -using Gtk 4.0; -using Adw 1; - -template $LibraryView: Adw.Bin { - Box { - orientation: vertical; - - Adw.StatusPage status_page { - vexpand: true; - hexpand: true; - icon-name: "library-symbolic"; - title: _("Library"); - description: _("Add items here from your bottle\'s program list"); - } - - ScrolledWindow scroll_window { - hexpand: true; - vexpand: true; - - FlowBox main_flow { - max-children-per-line: bind template.items_per_line; - row-spacing: 5; - column-spacing: 5; - halign: center; - valign: start; - margin-top: 5; - margin-start: 5; - margin-bottom: 5; - margin-end: 5; - homogeneous: true; - selection-mode: none; - activate-on-single-click: false; - } - } - } -} diff --git a/bottles/frontend/library_entry.py b/bottles/frontend/library_entry.py deleted file mode 100644 index 447ec7b11a1..00000000000 --- a/bottles/frontend/library_entry.py +++ /dev/null @@ -1,194 +0,0 @@ -# library_entry.py -# -# Copyright 2025 The Bottles Contributors -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, in version 3 of the License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# - -from gettext import gettext as _ - -from gi.repository import Gtk, Gdk - -import logging -from bottles.backend.managers.library import LibraryManager -from bottles.backend.managers.thumbnail import ThumbnailManager -from bottles.backend.models.result import Result -from bottles.backend.utils.threading import RunAsync -from bottles.backend.wine.executor import WineExecutor -from bottles.backend.wine.winedbg import WineDbg -from bottles.frontend.gtk import GtkUtils - - -@Gtk.Template(resource_path="/com/usebottles/bottles/library-entry.ui") -class LibraryEntry(Gtk.Box): - __gtype_name__ = "LibraryEntry" - - # region Widgets - btn_run = Gtk.Template.Child() - btn_stop = Gtk.Template.Child() - btn_remove = Gtk.Template.Child() - label_name = Gtk.Template.Child() - label_bottle = Gtk.Template.Child() - label_no_cover = Gtk.Template.Child() - img_cover = Gtk.Template.Child() - revealer_run = Gtk.Template.Child() - revealer_details = Gtk.Template.Child() - overlay = Gtk.Template.Child() - - # endregion - - def __init__(self, library, uuid, entry, *args, **kwargs): - super().__init__(*args, **kwargs) - self.library = library - self.window = library.window - self.manager = library.window.manager - self.name = entry["name"] - self.uuid = uuid - self.entry = entry - self.config = self.__get_config() - - # This happens when a Library entry is an "orphan" (no bottles associated) - if self.config is None: - library_manager = LibraryManager() - library_manager.remove_from_library(self.uuid) - raise Exception - - self.program = self.__get_program() - - if len(entry["name"]) >= 15: - name = entry["name"][:13] + "…" - else: - name = entry["name"] - - self.label_name.set_text(name) - self.label_bottle.set_text(entry["bottle"]["name"]) - self.label_no_cover.set_label(self.name) - - if entry.get("thumbnail"): - path = ThumbnailManager.get_path(self.config, entry["thumbnail"]) - - if path is None: - # redownloading *should* never fail as it was successfully downloaded before - logging.info("Redownloading grid image...") - library_manager = LibraryManager() - result = library_manager.download_thumbnail(self.uuid, self.config) - if result: - entry = library_manager.get_library().get(uuid) - path = ThumbnailManager.get_path(self.config, entry["thumbnail"]) - - if path is not None: - # Gtk.Picture.set_pixbuf deprecated in GTK 4.12 - texture = Gdk.Texture.new_from_filename(path) - self.img_cover.set_paintable(texture) - self.img_cover.set_visible(True) - self.label_no_cover.set_visible(False) - - motion_ctrl = Gtk.EventControllerMotion.new() - motion_ctrl.connect("enter", self.__on_motion_enter) - motion_ctrl.connect("leave", self.__on_motion_leave) - self.overlay.add_controller(motion_ctrl) - self.btn_run.connect("clicked", self.run_executable) - self.btn_stop.connect("clicked", self.stop_process) - self.btn_remove.connect("clicked", self.__remove_entry) - - def __get_config(self): - bottles = self.manager.local_bottles - if self.entry["bottle"]["name"] in bottles: - return bottles[self.entry["bottle"]["name"]] - parent = self.get_parent() - if parent: - parent.remove(self) # TODO: Remove from list - - def __get_program(self): - programs = self.manager.get_programs(self.config) - programs = [ - p - for p in programs - if p["id"] == self.entry["id"] or p["name"] == self.entry["name"] - ] - if len(programs) == 0: - return None # TODO: remove entry from library - return programs[0] - - @GtkUtils.run_in_main_loop - def __reset_buttons(self, result: Result | bool = None, error=False): - match result: - case Result(): - status = result.status - case bool(): - status = result - case _: - logging.error( - f"result should be Result or bool, but it was {type(result)}" - ) - status = False - - self.btn_remove.set_visible(status) - self.btn_stop.set_visible(not status) - self.btn_run.set_visible(status) - - def __is_alive(self): - winedbg = WineDbg(self.config) - - @GtkUtils.run_in_main_loop - def set_watcher(result=False, error=False): - nonlocal winedbg - self.__reset_buttons() - - RunAsync( - winedbg.wait_for_process, - callback=self.__reset_buttons, - name=self.program["executable"], - timeout=5, - ) - - RunAsync( - winedbg.is_process_alive, - callback=set_watcher, - name=self.program["executable"], - ) - - def __remove_entry(self, *args): - self.library.remove_entry(self) - - def run_executable(self, widget, with_terminal=False): - self.window.show_toast(_('Launching "{0}"…').format(self.program["name"])) - RunAsync( - WineExecutor.run_program, - callback=self.__reset_buttons, - config=self.config, - program=self.program, - ) - self.__reset_buttons() - - def stop_process(self, widget): - self.window.show_toast(_('Stopping "{0}"…').format(self.program["name"])) - winedbg = WineDbg(self.config) - winedbg.kill_process(name=self.program["executable"]) - self.__reset_buttons(True) - - def __on_motion_enter(self, *args): - self.revealer_run.set_reveal_child(True) - self.revealer_details.set_reveal_child(True) - - def __on_motion_leave(self, *args): - self.revealer_run.set_reveal_child(False) - self.revealer_details.set_reveal_child(False) - - # hide() and show() are essentialy workarounds to avoid keeping - # the empty space of the hidden entry in the GtkFlowBox - def hide(self): - self.get_parent().set_visible(False) - - def show(self): - self.get_parent().set_visible(True) diff --git a/bottles/frontend/library_view.py b/bottles/frontend/library_view.py deleted file mode 100644 index c3cba16347b..00000000000 --- a/bottles/frontend/library_view.py +++ /dev/null @@ -1,90 +0,0 @@ -# library_view.py -# -# Copyright 2025 The Bottles Contributors -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, in version 3 of the License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# - -import contextlib -from gettext import gettext as _ - -from gi.repository import Gtk, Adw, GObject - -from bottles.backend.managers.library import LibraryManager -from bottles.frontend.gtk import GtkUtils -from bottles.frontend.library_entry import LibraryEntry - - -@Gtk.Template(resource_path="/com/usebottles/bottles/library-view.ui") -class LibraryView(Adw.Bin): - __gtype_name__ = "LibraryView" - - # region Widgets - scroll_window = Gtk.Template.Child() - main_flow = Gtk.Template.Child() - status_page = Gtk.Template.Child() - style_provider = Gtk.CssProvider() - # endregion - - items_per_line = GObject.property(type=int, default=0) # type: ignore - - def __init__(self, window, **kwargs): - super().__init__(**kwargs) - self.window = window - self.css = b"" - self.update() - - def update(self): - library_manager = LibraryManager() - entries = library_manager.get_library() - - while self.main_flow.get_first_child() is not None: - self.main_flow.remove(self.main_flow.get_first_child()) - - self.status_page.set_visible(len(entries) == 0) - self.scroll_window.set_visible(not len(entries) == 0) - - self.items_per_line = len(entries) - - for u, e in entries.items(): - # We suppress exceptions so that it doesn't continue if the init fails - with contextlib.suppress(Exception): - entry = LibraryEntry(self, u, e) - self.main_flow.append(entry) - - def remove_entry(self, entry): - @GtkUtils.run_in_main_loop - def undo_callback(*args): - self.items_per_line += 1 - entry.show() - - @GtkUtils.run_in_main_loop - def dismissed_callback(*args): - self.__delete_entry(entry) - - entry.hide() - self.items_per_line -= 1 - self.window.show_toast( - message=_('"{0}" removed from the library.').format(entry.name), - timeout=5, - action_label=_("Undo"), - action_callback=undo_callback, - dismissed_callback=dismissed_callback, - ) - - def __delete_entry(self, entry): - library_manager = LibraryManager() - library_manager.remove_from_library(entry.uuid) - - def go_back(self, widget=False): - self.window.main_leaf.navigate(Adw.NavigationDirection.BACK) diff --git a/bottles/frontend/meson.build b/bottles/frontend/meson.build index fc4dee2e5bf..cd08cb04674 100644 --- a/bottles/frontend/meson.build +++ b/bottles/frontend/meson.build @@ -36,8 +36,6 @@ blueprints = custom_target('blueprints', 'dll-override-entry.blp', 'drive-entry.blp', 'env-var-entry.blp', - 'library-entry.blp', - 'library-view.blp', 'bottle-row.blp', 'bottles-list-view.blp', 'loading-view.blp', @@ -87,7 +85,6 @@ bottles_sources = [ 'sh.py', 'new_bottle_dialog.py', 'bottles_list_view.py', - 'library_view.py', 'bottle_details_view.py', 'preferences.py', 'loading_view.py', @@ -99,7 +96,6 @@ bottles_sources = [ 'executable.py', 'program_row.py', 'component_entry_row.py', - 'library_entry.py', 'crash_report_dialog.py', 'dll_overrides_dialog.py', 'environment_variables_dialog.py', diff --git a/bottles/frontend/program-row.blp b/bottles/frontend/program-row.blp index 7c51a6e95bf..055543e00da 100644 --- a/bottles/frontend/program-row.blp +++ b/bottles/frontend/program-row.blp @@ -39,10 +39,6 @@ Popover pop_actions { text: _("Change Launch Options…"); } - $GtkModelButton btn_add_library { - text: _("Add to Library"); - } - $GtkModelButton btn_add_entry { text: _("Add Desktop Entry"); } diff --git a/bottles/frontend/program_row.py b/bottles/frontend/program_row.py index 77928eff77c..d411594035d 100644 --- a/bottles/frontend/program_row.py +++ b/bottles/frontend/program_row.py @@ -20,7 +20,6 @@ from gi.repository import Gtk, Adw -from bottles.backend.managers.library import LibraryManager from bottles.backend.models.result import Result from bottles.backend.utils.manager import ManagerUtils from bottles.backend.utils.threading import RunAsync @@ -50,7 +49,6 @@ class ProgramRow(Adw.ActionRow): btn_browse = Gtk.Template.Child() btn_add_steam = Gtk.Template.Child() btn_add_entry = Gtk.Template.Child() - btn_add_library = Gtk.Template.Child() btn_launch_terminal = Gtk.Template.Child() pop_actions = Gtk.Template.Child() @@ -81,11 +79,6 @@ def __init__( self.btn_hide.set_visible(not program.get("removed")) self.btn_unhide.set_visible(program.get("removed")) - library_manager = LibraryManager() - for _uuid, entry in library_manager.get_library().items(): - if entry.get("id") == program.get("id"): - self.btn_add_library.set_visible(False) - external_programs = [] for v in self.config.External_Programs.values(): external_programs.append(v["name"]) @@ -101,7 +94,6 @@ def __init__( self.btn_rename.connect("clicked", self.rename_program) self.btn_browse.connect("clicked", self.browse_program_folder) self.btn_add_entry.connect("clicked", self.add_entry) - self.btn_add_library.connect("clicked", self.add_to_library) self.btn_remove.connect("clicked", self.remove_program) if not program.get("removed") and not is_steam and check_boot: @@ -229,28 +221,11 @@ def func(new_name): scope="External_Programs", ) - def async_work(): - library_manager = LibraryManager() - entries = library_manager.get_library() - - for uuid, entry in entries.items(): - if entry.get("id") == self.program["id"]: - entries[uuid]["name"] = new_name - library_manager.download_thumbnail(uuid, self.config) - break - - library_manager.__library = entries - library_manager.save_library() - - @GtkUtils.run_in_main_loop - def ui_update(_result, _error): - self.window.page_library.update() - self.window.show_toast( - _('"{0}" renamed to "{1}"').format(old_name, new_name) - ) - self.update_programs() - - RunAsync(async_work, callback=ui_update) + self.window.page_library.update() + self.window.show_toast( + _('"{0}" renamed to "{1}"').format(old_name, new_name) + ) + self.update_programs() dialog = RenameProgramDialog( self.window, on_save=func, name=self.program["name"] @@ -284,28 +259,3 @@ def update(result, _error=False): "path": self.program["path"], }, ) - - def add_to_library(self, _widget): - def update(_result, _error=False): - self.window.update_library() - self.window.show_toast( - _('"{0}" added to your library').format(self.program["name"]) - ) - - def add_to_library(): - self.save_program() # we need to store it in the bottle configuration to keep the reference - library_manager = LibraryManager() - library_manager.add_to_library( - { - "bottle": {"name": self.config.Name, "path": self.config.Path}, - "name": self.program["name"], - "id": str(self.program["id"]), - "icon": ManagerUtils.extract_icon( - self.config, self.program["name"], self.program["path"] - ), - }, - self.config, - ) - - self.btn_add_library.set_visible(False) - RunAsync(add_to_library, update) diff --git a/bottles/frontend/window.py b/bottles/frontend/window.py index 37f1a3f6f5e..ca84771c85f 100644 --- a/bottles/frontend/window.py +++ b/bottles/frontend/window.py @@ -34,7 +34,6 @@ from bottles.frontend.params import APP_ID, BASE_ID, PROFILE from bottles.frontend.gtk import GtkUtils from bottles.frontend.bottle_details_view import BottleDetailsView -from bottles.frontend.library_view import LibraryView from bottles.frontend.bottles_list_view import BottlesListView from bottles.frontend.loading_view import LoadingView from bottles.frontend.new_bottle_dialog import NewBottleDialog @@ -176,9 +175,6 @@ def g_show_uri_handler(self, res: Result): # endregion - def update_library(self): - GLib.idle_add(self.page_library.update) - def title(self, title, subtitle: str = ""): self.view_switcher_title.set_title(title) self.view_switcher_title.set_subtitle(subtitle) @@ -203,7 +199,6 @@ def set_manager(result: Manager, error=None): # Pages self.page_details = BottleDetailsView(self) self.page_list = BottlesListView(self) - self.page_library = LibraryView(self) self.main_leaf.append(self.page_details) @@ -212,9 +207,6 @@ def set_manager(result: Manager, error=None): self.stack_main.add_titled( child=self.page_list, name="page_list", title=_("Bottles") ).set_icon_name(f"{APP_ID}-symbolic") - self.stack_main.add_titled( - child=self.page_library, name="page_library", title=_("Library") - ).set_icon_name("library-symbolic") self.page_list.search_bar.set_key_capture_widget(self) self.btn_search.bind_property( From ce4779c291da9bc4096780ec61f1af3509f12a5a Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Tue, 4 Feb 2025 09:37:52 -0500 Subject: [PATCH 126/146] backend: Remove LibraryManager --- bottles/backend/managers/library.py | 132 --------------------------- bottles/backend/managers/manager.py | 8 -- bottles/backend/managers/meson.build | 1 - 3 files changed, 141 deletions(-) delete mode 100644 bottles/backend/managers/library.py diff --git a/bottles/backend/managers/library.py b/bottles/backend/managers/library.py deleted file mode 100644 index 2b83c00f16e..00000000000 --- a/bottles/backend/managers/library.py +++ /dev/null @@ -1,132 +0,0 @@ -# library.py -# -# Copyright 2022 brombinmirko -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, in version 3 of the License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# - -import os -import uuid - -from bottles.backend.models.config import BottleConfig -from bottles.backend.utils import yaml - -import logging -from bottles.backend.globals import Paths -from bottles.backend.managers.steamgriddb import SteamGridDBManager - - -class LibraryManager: - """ - The LibraryManager class is used to store and retrieve data - from the user library.yml file. - """ - - library_path: str = Paths.library - __library: dict = {} - - def __init__(self): - self.load_library(silent=True) - - def load_library(self, silent=False): - """ - Loads data from the library.yml file. - """ - if not os.path.exists(self.library_path): - logging.warning("Library file not found, creating new one") - self.__library = {} - self.save_library() - else: - with open(self.library_path) as library_file: - self.__library = yaml.load(library_file) - - if self.__library is None: - self.__library = {} - - _tmp = self.__library.copy() - for k, v in _tmp.items(): - if "id" not in v: - del self.__library[k] - - self.save_library(silent=silent) - - def add_to_library(self, data: dict, config: BottleConfig): - """ - Adds a new entry to the library.yml file. - """ - if self.__already_in_library(data): - logging.warning(f"Entry already in library, nothing to add: {data}") - return - - _uuid = str(uuid.uuid4()) - logging.info(f"Adding new entry to library: {_uuid}") - - if not data.get("thumbnail"): - data["thumbnail"] = SteamGridDBManager.get_game_grid(data["name"], config) - - self.__library[_uuid] = data - self.save_library() - - def download_thumbnail(self, _uuid: str, config: BottleConfig): - if not self.__library.get(_uuid): - logging.warning( - f"Entry not found in library, can't download thumbnail: {_uuid}" - ) - return False - - data = self.__library.get(_uuid) - value = SteamGridDBManager.get_game_grid(data["name"], config) - - if not value: - return False - - self.__library[_uuid]["thumbnail"] = value - self.save_library() - return True - - def __already_in_library(self, data: dict): - """ - Checks if the entry UUID is already in the library.yml file. - """ - for k, v in self.__library.items(): - if v["id"] == data["id"]: - return True - - return False - - def remove_from_library(self, _uuid: str): - """ - Removes an entry from the library.yml file. - """ - if self.__library.get(_uuid): - logging.info(f"Removing entry from library: {_uuid}") - del self.__library[_uuid] - self.save_library() - return - logging.warning(f"Entry not found in library, nothing to remove: {_uuid}") - - def save_library(self, silent=False): - """ - Saves the library.yml file. - """ - with open(self.library_path, "w") as library_file: - yaml.dump(self.__library, library_file) - - if not silent: - logging.info("Library saved") - - def get_library(self): - """ - Returns the library.yml file. - """ - return self.__library diff --git a/bottles/backend/managers/manager.py b/bottles/backend/managers/manager.py index 26241bfe055..17c9af8805a 100644 --- a/bottles/backend/managers/manager.py +++ b/bottles/backend/managers/manager.py @@ -36,7 +36,6 @@ from bottles.backend.dlls.vkd3d import VKD3DComponent from bottles.backend.globals import Paths import logging -from bottles.backend.managers.library import LibraryManager from bottles.backend.managers.template import TemplateManager from bottles.backend.models.config import BottleConfig from bottles.backend.models.result import Result @@ -1237,13 +1236,6 @@ def delete_bottle(self, config: BottleConfig) -> bool: for inst in glob(f"{Paths.applications}/{config.Name}--*"): os.remove(inst) - logging.info("Removing library entries associated with this bottle…") - library_manager = LibraryManager() - entries = library_manager.get_library().copy() - for _uuid, entry in entries.items(): - if entry.get("bottle").get("name") == config.Name: - library_manager.remove_from_library(_uuid) - if config.Custom_Path: logging.info("Removing placeholder…") with contextlib.suppress(FileNotFoundError): diff --git a/bottles/backend/managers/meson.build b/bottles/backend/managers/meson.build index bbe7b30c0ed..822bddf442e 100644 --- a/bottles/backend/managers/meson.build +++ b/bottles/backend/managers/meson.build @@ -3,7 +3,6 @@ managersdir = join_paths(pkgdatadir, 'bottles/backend/managers') bottles_sources = [ '__init__.py', - 'library.py', 'manager.py', 'conf.py', 'template.py', From b2648c7fe50e0e99ae40043b7b29be94a406213a Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Tue, 4 Feb 2025 10:52:11 -0500 Subject: [PATCH 127/146] backend: Remove ThumbnailManager --- bottles/backend/managers/meson.build | 1 - bottles/backend/managers/thumbnail.py | 47 --------------------------- 2 files changed, 48 deletions(-) delete mode 100644 bottles/backend/managers/thumbnail.py diff --git a/bottles/backend/managers/meson.build b/bottles/backend/managers/meson.build index 822bddf442e..ad60235d925 100644 --- a/bottles/backend/managers/meson.build +++ b/bottles/backend/managers/meson.build @@ -8,7 +8,6 @@ bottles_sources = [ 'template.py', 'sandbox.py', 'steamgriddb.py', - 'thumbnail.py' ] install_data(bottles_sources, install_dir: managersdir) diff --git a/bottles/backend/managers/thumbnail.py b/bottles/backend/managers/thumbnail.py deleted file mode 100644 index b63d750d1e4..00000000000 --- a/bottles/backend/managers/thumbnail.py +++ /dev/null @@ -1,47 +0,0 @@ -# thumbnail.py -# -# Copyright 2022 brombinmirko -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, in version 3 of the License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# - -import os - -import logging -from bottles.backend.models.config import BottleConfig -from bottles.backend.utils.manager import ManagerUtils - - -class ThumbnailManager: - @staticmethod - def get_path(config: BottleConfig, uri: str): - if uri.startswith("grid:"): - return ThumbnailManager.__load_grid(config, uri) - # elif uri.startswith("epic:"): - # return ThumbnailManager.__load_epic(config, uri) - # elif uri.startswith("origin:"): - # return ThumbnailManager.__load_origin(config, uri) - logging.error("Unknown URI: " + uri) - return None - - @staticmethod - def __load_grid(config: BottleConfig, uri: str): - bottle_path = ManagerUtils.get_bottle_path(config) - file_name = uri[5:] - path = os.path.join(bottle_path, "grids", file_name) - - if not os.path.exists(path): - logging.error("Grid not found: " + path) - return None - - return path From 003ca54bfa4be8d53754ed7d721e6650e6987d16 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Tue, 4 Feb 2025 11:03:54 -0500 Subject: [PATCH 128/146] backend: Remove TemplateManager --- bottles/backend/managers/manager.py | 85 ------------ bottles/backend/managers/meson.build | 1 - bottles/backend/managers/template.py | 198 --------------------------- 3 files changed, 284 deletions(-) delete mode 100644 bottles/backend/managers/template.py diff --git a/bottles/backend/managers/manager.py b/bottles/backend/managers/manager.py index 17c9af8805a..0b1240ba3d9 100644 --- a/bottles/backend/managers/manager.py +++ b/bottles/backend/managers/manager.py @@ -36,7 +36,6 @@ from bottles.backend.dlls.vkd3d import VKD3DComponent from bottles.backend.globals import Paths import logging -from bottles.backend.managers.template import TemplateManager from bottles.backend.models.config import BottleConfig from bottles.backend.models.result import Result from bottles.backend.models.samples import Samples @@ -1018,18 +1017,7 @@ def components_check(): if versioning: config.Versioning = True - # get template - template = TemplateManager.get_env_template(environment) - template_updated = False - if template: - log_update(_("Template found, applying…")) - TemplateManager.unpack_template(template, config) - config.Installed_Dependencies = template["config"]["Installed_Dependencies"] - config.Uninstallers = template["config"]["Uninstallers"] - # initialize wineprefix - reg = Reg(config) - rk = RegKeys(config) wineboot = WineBoot(config) wineserver = WineServer(config) @@ -1078,37 +1066,6 @@ def components_check(): # wait for registry files to be created FileUtils.wait_for_files(reg_files) - # apply Windows version - if not template and not custom_environment: - logging.info("Setting Windows version…") - log_update(_("Setting Windows version…")) - if ( - "soda" not in runner_name.lower() and "caffe" not in runner_name.lower() - ): # Caffe/Soda came with win10 by default - rk.lg_set_windows(config.Windows) - wineboot.update() - - FileUtils.wait_for_files(reg_files) - - # apply CMD settings - logging.info("Setting CMD default settings…") - log_update(_("Apply CMD default settings…")) - rk.apply_cmd_settings() - wineboot.update() - - FileUtils.wait_for_files(reg_files) - - # blacklisting processes - logging.info("Optimizing environment…") - log_update(_("Optimizing environment…")) - _blacklist_dll = ["winemenubuilder.exe"] - for _dll in _blacklist_dll: - reg.add( - key="HKEY_CURRENT_USER\\Software\\Wine\\DllOverrides", - value=_dll, - data="", - ) - # apply environment configuration logging.info(f"Applying environment: [{environment}]…") log_update(_("Applying environment: {0}…").format(environment)) @@ -1137,42 +1094,6 @@ def components_check(): if prm in env.get("Parameters", {}): config.Parameters[prm] = env["Parameters"][prm] - if (not template and config.Parameters.dxvk) or ( - template and template["config"]["DXVK"] != dxvk - ): - # perform dxvk installation if configured - logging.info("Installing DXVK…") - log_update(_("Installing DXVK…")) - self.install_dll_component(config, "dxvk", version=dxvk_name) - template_updated = True - - if ( - not template - and config.Parameters.vkd3d - or (template and template["config"]["VKD3D"] != vkd3d) - ): - # perform vkd3d installation if configured - logging.info("Installing VKD3D…") - log_update(_("Installing VKD3D…")) - self.install_dll_component(config, "vkd3d", version=vkd3d_name) - template_updated = True - - if ( - not template - and config.Parameters.dxvk_nvapi - or (template and template["config"]["NVAPI"] != nvapi) - ): - if GPUUtils.is_gpu(GPUVendors.NVIDIA): - # perform nvapi installation if configured - logging.info("Installing DXVK-NVAPI…") - log_update(_("Installing DXVK-NVAPI…")) - self.install_dll_component(config, "nvapi", version=nvapi_name) - template_updated = True - - for dep in env.get("Installed_Dependencies", []): - if template and dep in template["config"]["Installed_Dependencies"]: - continue - # save bottle config config.dump(f"{bottle_complete_path}/bottle.yml") @@ -1186,12 +1107,6 @@ def components_check(): # perform wineboot wineboot.update() - # caching template - if not template or template_updated: - logging.info("Caching template…") - log_update(_("Caching template…")) - TemplateManager.new(environment, config) - return Result(status=True, data={"config": config}) @staticmethod diff --git a/bottles/backend/managers/meson.build b/bottles/backend/managers/meson.build index ad60235d925..9f13827da34 100644 --- a/bottles/backend/managers/meson.build +++ b/bottles/backend/managers/meson.build @@ -5,7 +5,6 @@ bottles_sources = [ '__init__.py', 'manager.py', 'conf.py', - 'template.py', 'sandbox.py', 'steamgriddb.py', ] diff --git a/bottles/backend/managers/template.py b/bottles/backend/managers/template.py deleted file mode 100644 index 0cde2eb135e..00000000000 --- a/bottles/backend/managers/template.py +++ /dev/null @@ -1,198 +0,0 @@ -# template.py -# -# Copyright 2022 brombinmirko -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, in version 3 of the License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# - -import os - -from bottles.backend.models.config import BottleConfig -from bottles.backend.utils import yaml -import uuid -import shutil -import contextlib -from datetime import datetime -from pathlib import Path - -import logging -from bottles.backend.utils.manager import ManagerUtils -from bottles.backend.globals import Paths -from bottles.backend.models.samples import Samples - - -class TemplateManager: - @staticmethod - def new(env: str, config: BottleConfig): - env = env.lower() - templates = TemplateManager.get_templates() - - for template in templates: - if template["env"] == env: - logging.info(f"Caching new template for {env}…") - TemplateManager.delete_template(template["uuid"]) - - _uuid = str(uuid.uuid4()) - logging.info(f"Creating new template: {_uuid}") - bottle = ManagerUtils.get_bottle_path(config) - - delattr(config, "Name") - delattr(config, "Path") - delattr(config, "Creation_Date") - delattr(config, "Update_Date") - - ignored = ["dosdevices", "states", ".fvs", "*.yml" ".*"] - - _path = os.path.join(Paths.templates, _uuid) - logging.info("Copying files …") - - with contextlib.suppress(FileNotFoundError): - shutil.copytree( - bottle, _path, symlinks=True, ignore=shutil.ignore_patterns(*ignored) - ) - - template = { - "uuid": _uuid, - "env": env, - "created": datetime.now().strftime("%Y-%m-%d %H:%M:%S"), - "config": config, - } - - with open(os.path.join(_path, "template.yml"), "w") as f: - yaml.dump(template, f) - - logging.info(f"New template {env} created") - - if not TemplateManager.__validate_template(_uuid): - logging.error("Template validation failed, will retry with next bottle.") - shutil.rmtree(_path) - - @staticmethod - def __validate_template(template_uuid: str): - result = True - template_path = os.path.join(Paths.templates, template_uuid) - essentials = [ - "drive_c/ProgramData", - "drive_c/windows", - ] - - if not os.path.exists(template_path): - logging.error(f"Template {template_uuid} not found!") - result = False - - for essential in essentials: - if not os.path.exists(os.path.join(template_path, essential)): - logging.error( - f"Template {template_uuid} is missing essential path: {essential}" - ) - result = False - - path_size = sum(file.stat().st_size for file in Path(template_path).rglob("*")) - if path_size < 300000000: - logging.error(f"Template {template_uuid} is too small!") - result = False - - with open(os.path.join(template_path, "template.yml")) as f: - template = yaml.load(f) - if template["uuid"] != template_uuid: - logging.error(f"Template {template_uuid} has invalid uuid!") - result = False - - return result - - @staticmethod - def get_template_manifest(template: str): - with open(os.path.join(Paths.templates, template, "template.yml")) as f: - return yaml.load(f) - - @staticmethod - def get_templates(): - res = [] - templates = os.listdir(Paths.templates) - - for template in templates: - if os.path.exists(os.path.join(Paths.templates, template, "template.yml")): - _manifest = TemplateManager.get_template_manifest(template) - if _manifest is not None: - res.append(_manifest) - - return res - - @staticmethod - def delete_template(template_uuid: str): - if not template_uuid: - logging.error("Template uuid is not defined!") - return - - if not os.path.exists(os.path.join(Paths.templates, template_uuid)): - logging.error(f"Template {template_uuid} not found!") - return - - logging.info(f"Deleting template: {template_uuid}") - shutil.rmtree(os.path.join(Paths.templates, template_uuid)) - logging.info("Template deleted successfully!") - - @staticmethod - def check_outdated(template: dict): - env = template.get("env", "") - if env not in Samples.environments: - TemplateManager.delete_template(template.get("uuid")) - return True - - _sample = Samples.environments[env] - for p in _sample.get("Parameters", {}): - _params = template.get("config", {}).get("Parameters", {}) - if p not in _params or _params[p] != _sample["Parameters"][p]: - TemplateManager.delete_template(template.get("uuid")) - return True - - for d in _sample.get("Installed_Dependencies", []): - _deps = template.get("config", {}).get("Installed_Dependencies", []) - if d not in _deps: - TemplateManager.delete_template(template.get("uuid")) - return True - - return False - - @staticmethod - def get_env_template(env: str): - _templates = TemplateManager.get_templates() - for template in _templates: - if template["env"] == env.lower(): - if TemplateManager.check_outdated(template): - logging.info(f"Deleting outdated template: {template['uuid']}") - return None - return template - return None - - @staticmethod - def unpack_template(template: dict, config: BottleConfig): - def copy_func(source: str, dest: str): - if os.path.islink(source): - # we don't want symlinks from templates - return - shutil.copy2(source, dest) - - logging.info(f"Unpacking template: {template['uuid']}") - bottle = ManagerUtils.get_bottle_path(config) - _path = os.path.join(Paths.templates, template["uuid"]) - - shutil.copytree( - _path, - bottle, - symlinks=True, - dirs_exist_ok=True, - ignore=shutil.ignore_patterns(".*"), - ignore_dangling_symlinks=True, - ) - logging.info("Template unpacked successfully!") From 9d1d3784f1f069e88c23a572ec8462095a9b1a62 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Tue, 4 Feb 2025 11:12:56 -0500 Subject: [PATCH 129/146] backend: Remove ConfigManager --- bottles/backend/managers/conf.py | 139 --------------------------- bottles/backend/managers/meson.build | 1 - 2 files changed, 140 deletions(-) delete mode 100644 bottles/backend/managers/conf.py diff --git a/bottles/backend/managers/conf.py b/bottles/backend/managers/conf.py deleted file mode 100644 index 2936700746b..00000000000 --- a/bottles/backend/managers/conf.py +++ /dev/null @@ -1,139 +0,0 @@ -import os -from configparser import ConfigParser - -from bottles.backend.utils import yaml, json - - -class ConfigManager: - def __init__( - self, - config_file: str | None = None, - config_type: str = "ini", - config_string: str | None = None, - ): - self.config_file = config_file - self.config_string = config_string - self.config_type = config_type - - if self.config_file is not None: - self.checks() - - self.config_dict = self.read() - - if self.config_file is not None and self.config_string is not None: - raise ValueError( - "Passing both config_file and config_string is not allowed" - ) - - def checks(self): - """Checks if the configuration file exists, if not, create it.""" - if not os.path.exists(self.config_file): - base_path = os.path.dirname(self.config_file) - os.makedirs(base_path, exist_ok=True) - - with open(self.config_file, "w") as f: - f.write("") - - def read(self): - if self.config_file is not None: - """Reads the configuration file and returns it as a dictionary""" - if self.config_type == "ini": - config = ConfigParser() - config.read(self.config_file) - # noinspection PyProtectedMember - res = config._sections - elif self.config_type == "json": - with open(self.config_file) as f: - res = json.load(f) - elif self.config_type == "yaml" or self.config_type == "yml": - with open(self.config_file) as f: - res = yaml.load(f) - else: - raise ValueError("Invalid configuration type") - elif self.config_string is not None: - if self.config_type == "ini": - config = ConfigParser() - config.read_string(self.config_string) - res = config._sections - elif self.config_type == "json": - res = json.loads(self.config_string) - elif self.config_type == "yaml" or self.config_type == "yml": - res = yaml.load(self.config_string) - else: - raise ValueError("Invalid configuration type") - else: - res = None - - return res or {} - - def get_dict(self): - """Returns the configuration as a dictionary""" - return self.config_dict - - def write_json(self): - """Writes the configuration to a JSON file""" - with open(self.config_file, "w") as f: - json.dump(self.config_dict, f, indent=4) - - def write_yaml(self): - """Writes the configuration to a YAML file""" - with open(self.config_file, "w") as f: - yaml.dump(self.config_dict, f) - - def write_ini(self): - """Writes the configuration to an INI file""" - config = ConfigParser() - - for section in self.config_dict: - config.add_section(section) - - for key, value in self.config_dict[section].items(): - config.set(section, key, value) - - with open(self.config_file, "w") as f: - config.write(f) - - def write_dict(self, config_file: str | None = None): - if self.config_file is None and config_file is None: - raise ValueError("No config path specified") - elif self.config_file is None and config_file is not None: - self.config_file = config_file - - """Writes the configuration to the file""" - if self.config_type == "ini": - self.write_ini() - elif self.config_type == "json": - self.write_json() - elif self.config_type == "yaml": - self.write_yaml() - else: - raise ValueError("Invalid configuration type") - - def merge_dict(self, changes: dict): - """Merges a dictionary into the configuration""" - for section in changes: - if section in self.config_dict: - for key, value in changes[section].items(): - if isinstance(value, dict): - if key in self.config_dict[section]: - self.config_dict[section][key].update(value) - else: - self.config_dict[section][key] = value - else: - self.config_dict[section][key] = value - else: - self.config_dict[section] = changes[section] - - self.write_dict() - - def del_key(self, key_struct: dict): - """Deletes a key from the configuration""" - key = self.config_dict - - for i, k in enumerate(key_struct): - if i == len(key_struct) - 1: - del key[k] - continue - key = key[k] - - self.write_dict() diff --git a/bottles/backend/managers/meson.build b/bottles/backend/managers/meson.build index 9f13827da34..f423165c8a7 100644 --- a/bottles/backend/managers/meson.build +++ b/bottles/backend/managers/meson.build @@ -4,7 +4,6 @@ managersdir = join_paths(pkgdatadir, 'bottles/backend/managers') bottles_sources = [ '__init__.py', 'manager.py', - 'conf.py', 'sandbox.py', 'steamgriddb.py', ] From e536d7f67fc6d0aaa38d824b7b2d371c06fecbc4 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Tue, 4 Feb 2025 11:13:25 -0500 Subject: [PATCH 130/146] backend: Remove SteamGridDBManager --- bottles/backend/managers/meson.build | 1 - bottles/backend/managers/steamgriddb.py | 54 ------------------------- 2 files changed, 55 deletions(-) delete mode 100644 bottles/backend/managers/steamgriddb.py diff --git a/bottles/backend/managers/meson.build b/bottles/backend/managers/meson.build index f423165c8a7..8772ae1d333 100644 --- a/bottles/backend/managers/meson.build +++ b/bottles/backend/managers/meson.build @@ -5,7 +5,6 @@ bottles_sources = [ '__init__.py', 'manager.py', 'sandbox.py', - 'steamgriddb.py', ] install_data(bottles_sources, install_dir: managersdir) diff --git a/bottles/backend/managers/steamgriddb.py b/bottles/backend/managers/steamgriddb.py deleted file mode 100644 index f87277c9959..00000000000 --- a/bottles/backend/managers/steamgriddb.py +++ /dev/null @@ -1,54 +0,0 @@ -# steamgriddb.py -# -# Copyright 2022 brombinmirko -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, in version 3 of the License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# - -import os -import uuid -import requests - -from bottles.backend.models.config import BottleConfig -from bottles.backend.utils.manager import ManagerUtils - - -class SteamGridDBManager: - @staticmethod - def get_game_grid(name: str, config: BottleConfig): - try: - res = requests.get(f"https://steamgrid.usebottles.com/api/search/{name}") - except: - return - - if res.status_code == 200: - return SteamGridDBManager.__save_grid(res.json(), config) - - @staticmethod - def __save_grid(url: str, config: BottleConfig): - grids_path = os.path.join(ManagerUtils.get_bottle_path(config), "grids") - if not os.path.exists(grids_path): - os.makedirs(grids_path) - - ext = url.split(".")[-1] - filename = str(uuid.uuid4()) + "." + ext - path = os.path.join(grids_path, filename) - - try: - r = requests.get(url) - with open(path, "wb") as f: - f.write(r.content) - except Exception: - return - - return f"grid:{filename}" From 746d95f2cb807fd2b7c63542dd9ad889909e14a0 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Tue, 4 Feb 2025 11:40:42 -0500 Subject: [PATCH 131/146] backend: Remove SandboxManager --- bottles/backend/managers/meson.build | 1 - bottles/backend/managers/sandbox.py | 109 --------------------------- bottles/backend/wine/winecommand.py | 53 ++++--------- 3 files changed, 14 insertions(+), 149 deletions(-) delete mode 100644 bottles/backend/managers/sandbox.py diff --git a/bottles/backend/managers/meson.build b/bottles/backend/managers/meson.build index 8772ae1d333..36411328757 100644 --- a/bottles/backend/managers/meson.build +++ b/bottles/backend/managers/meson.build @@ -4,7 +4,6 @@ managersdir = join_paths(pkgdatadir, 'bottles/backend/managers') bottles_sources = [ '__init__.py', 'manager.py', - 'sandbox.py', ] install_data(bottles_sources, install_dir: managersdir) diff --git a/bottles/backend/managers/sandbox.py b/bottles/backend/managers/sandbox.py deleted file mode 100644 index 2f5661d994e..00000000000 --- a/bottles/backend/managers/sandbox.py +++ /dev/null @@ -1,109 +0,0 @@ -# steam.py -# -# Copyright 2022 brombinmirko -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, in version 3 of the License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# - - -import os -import shlex -import subprocess - - -class SandboxManager: - def __init__( - self, - envs: dict | None = None, - chdir: str | None = None, - clear_env: bool = False, - share_paths_ro: list | None = None, - share_paths_rw: list | None = None, - share_net: bool = False, - share_user: bool = False, - share_host_ro: bool = True, - share_display: bool = True, - share_sound: bool = True, - share_gpu: bool = True, - ): - self.envs = envs - self.chdir = chdir - self.clear_env = clear_env - self.share_paths_ro = share_paths_ro - self.share_paths_rw = share_paths_rw - self.share_net = share_net - self.share_user = share_user - self.share_host_ro = share_host_ro - self.share_display = share_display - self.share_sound = share_sound - self.share_gpu = share_gpu - self.__uid = os.environ.get("UID", "1000") - - def __get_flatpak_spawn(self, cmd: str): - _cmd = ["flatpak-spawn"] - - if self.envs: - _cmd += [f"--env={k}={shlex.quote(v)}" for k, v in self.envs.items()] - - if self.share_host_ro: - _cmd.append("--sandbox") - _cmd.append("--sandbox-expose-path-ro=/") - - if self.chdir: - _cmd.append(f"--directory={shlex.quote(self.chdir)}") - _cmd.append(f"--sandbox-expose-path={shlex.quote(self.chdir)}") - - if self.clear_env: - _cmd.append("--clear-env") - - if self.share_paths_ro: - _cmd += [ - f"--sandbox-expose-path-ro={shlex.quote(p)}" - for p in self.share_paths_ro - ] - - if self.share_paths_rw: - _cmd += [ - f"--sandbox-expose-path={shlex.quote(p)}" for p in self.share_paths_rw - ] - - if not self.share_net: - _cmd.append("--no-network") - - if self.share_display: - _cmd.append("--sandbox-flag=share-display") - - if self.share_sound: - _cmd.append("--sandbox-flag=share-sound") - - if self.share_gpu: - _cmd.append("--sandbox-flag=share-gpu") - - _cmd.append(cmd) - - return _cmd - - def get_cmd(self, cmd: str): - _cmd = "" - if "FLATPAK_ID" in os.environ: - _cmd = self.__get_flatpak_spawn(cmd) - - return " ".join(_cmd) - - def run(self, cmd: str) -> subprocess.Popen[bytes]: - return subprocess.Popen( - self.get_cmd(cmd), - shell=True, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - ) diff --git a/bottles/backend/wine/winecommand.py b/bottles/backend/wine/winecommand.py index 334753bb36d..0237a532051 100644 --- a/bottles/backend/wine/winecommand.py +++ b/bottles/backend/wine/winecommand.py @@ -14,7 +14,6 @@ vmtouch_available, ) import logging -from bottles.backend.managers.sandbox import SandboxManager from bottles.backend.models.config import BottleConfig from bottles.backend.models.result import Result from bottles.backend.utils.display import DisplayUtils @@ -610,16 +609,6 @@ def _vmtouch_free(self): cwd=self.cwd, ) - def _get_sandbox_manager(self) -> SandboxManager: - return SandboxManager( - envs=self.env, - chdir=self.cwd, - share_paths_rw=[ManagerUtils.get_bottle_path(self.config)], - share_paths_ro=[Paths.runners, Paths.temp], - share_net=self.config.Sandbox.share_net, - share_sound=self.config.Sandbox.share_sound, - ) - def run(self) -> Result[str | None]: """ Run command with pre-configured parameters @@ -635,42 +624,28 @@ def run(self) -> Result[str | None]: if vmtouch_available and self.config.Parameters.vmtouch and not self.terminal: self._vmtouch_preload() - sandbox = ( - self._get_sandbox_manager() if self.config.Parameters.sandbox else None - ) - # run command in external terminal if terminal is True if self.terminal: - if sandbox: - return Result( - status=TerminalUtils().execute( - sandbox.get_cmd(self.command), self.env, self.colors, self.cwd - ) - ) - else: - return Result( - status=TerminalUtils().execute( - self.command, self.env, self.colors, self.cwd - ) + return Result( + status=TerminalUtils().execute( + self.command, self.env, self.colors, self.cwd ) + ) # prepare proc if we are going to execute command internally # proc should always be `Popen[bytes]` to make sure # stdout_data's type is `bytes` proc: subprocess.Popen[bytes] - if sandbox: - proc = sandbox.run(self.command) - else: - try: - proc = subprocess.Popen( - self.command, - stdout=subprocess.PIPE, - shell=True, - env=self.env, - cwd=self.cwd, - ) - except FileNotFoundError: - return Result(False, message="File not found") + try: + proc = subprocess.Popen( + self.command, + stdout=subprocess.PIPE, + shell=True, + env=self.env, + cwd=self.cwd, + ) + except FileNotFoundError: + return Result(False, message="File not found") stdout_data, _ = proc.communicate() From 7e23451ada8b76cfc39e07c13dfc9e81ae5a9f6f Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Tue, 4 Feb 2025 20:36:59 -0500 Subject: [PATCH 132/146] backend: Remove SteamUtils --- bottles/backend/managers/manager.py | 31 +++---- bottles/backend/runner.py | 1 - bottles/backend/utils/meson.build | 1 - bottles/backend/utils/steam.py | 133 ---------------------------- bottles/backend/wine/winecommand.py | 37 +------- bottles/backend/wine/wineserver.py | 15 ---- 6 files changed, 11 insertions(+), 207 deletions(-) delete mode 100644 bottles/backend/utils/steam.py diff --git a/bottles/backend/managers/manager.py b/bottles/backend/managers/manager.py index 0b1240ba3d9..e2c98485f60 100644 --- a/bottles/backend/managers/manager.py +++ b/bottles/backend/managers/manager.py @@ -49,7 +49,6 @@ from bottles.backend.utils.lnk import LnkUtils from bottles.backend.utils.manager import ManagerUtils from bottles.backend.utils.singleton import Singleton -from bottles.backend.utils.steam import SteamUtils from bottles.backend.utils.threading import RunAsync from bottles.backend.wine.reg import Reg from bottles.backend.wine.regkeys import RegKeys @@ -192,16 +191,15 @@ def check_runners(self, install_latest: bool = True) -> bool: # lock winemenubuilder.exe for runner in runners: - if not SteamUtils.is_proton(runner): - winemenubuilder_paths = [ - f"{runner}lib64/wine/x86_64-windows/winemenubuilder.exe", - f"{runner}lib/wine/x86_64-windows/winemenubuilder.exe", - f"{runner}lib32/wine/i386-windows/winemenubuilder.exe", - f"{runner}lib/wine/i386-windows/winemenubuilder.exe", - ] - for winemenubuilder in winemenubuilder_paths: - if os.path.isfile(winemenubuilder): - os.rename(winemenubuilder, f"{winemenubuilder}.lock") + winemenubuilder_paths = [ + f"{runner}lib64/wine/x86_64-windows/winemenubuilder.exe", + f"{runner}lib/wine/x86_64-windows/winemenubuilder.exe", + f"{runner}lib32/wine/i386-windows/winemenubuilder.exe", + f"{runner}lib/wine/i386-windows/winemenubuilder.exe", + ] + for winemenubuilder in winemenubuilder_paths: + if os.path.isfile(winemenubuilder): + os.rename(winemenubuilder, f"{winemenubuilder}.lock") # check system wine if shutil.which("wine") is not None: @@ -364,16 +362,7 @@ def get_offline_components( if component_type == "runner": offline_components = [ - runner - for runner in offline_components - if not runner.startswith("sys-") - and not SteamUtils.is_proton(ManagerUtils.get_runner_path(runner)) - ] - elif component_type == "runner:proton": - offline_components = [ - runner - for runner in offline_components - if SteamUtils.is_proton(ManagerUtils.get_runner_path(runner)) + runner for runner in offline_components if not runner.startswith("sys-") ] if ( diff --git a/bottles/backend/runner.py b/bottles/backend/runner.py index 94e4baffd09..8a7438da6c8 100644 --- a/bottles/backend/runner.py +++ b/bottles/backend/runner.py @@ -22,7 +22,6 @@ from bottles.backend.models.config import BottleConfig from bottles.backend.models.result import Result from bottles.backend.utils.manager import ManagerUtils -from bottles.backend.utils.steam import SteamUtils from bottles.backend.wine.wineboot import WineBoot if TYPE_CHECKING: diff --git a/bottles/backend/utils/meson.build b/bottles/backend/utils/meson.build index dc0a08b3b67..e75e2f9916b 100644 --- a/bottles/backend/utils/meson.build +++ b/bottles/backend/utils/meson.build @@ -12,7 +12,6 @@ bottles_sources = [ 'file.py', 'generic.py', 'wine.py', - 'steam.py', 'lnk.py', 'decorators.py', 'snake.py', diff --git a/bottles/backend/utils/steam.py b/bottles/backend/utils/steam.py deleted file mode 100644 index 5fcf9d9b97f..00000000000 --- a/bottles/backend/utils/steam.py +++ /dev/null @@ -1,133 +0,0 @@ -# steam.py -# -# Copyright 2022 brombinmirko -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, in version 3 of the License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# - -import os -import shlex -from typing import TextIO - -import logging -from bottles.backend.models.vdict import VDFDict -from bottles.backend.utils import vdf - - -class SteamUtils: - @staticmethod - def parse_acf(data: str) -> VDFDict: - """ - Parses an ACF file. Just a wrapper for vdf.loads. - """ - return vdf.loads(data) - - @staticmethod - def parse_vdf(data: str) -> VDFDict: - """ - Parses a VDF file. Just a wrapper for vdf.loads. - """ - return vdf.loads(data) - - @staticmethod - def to_vdf(data: VDFDict, fp: TextIO): - """ - Saves a VDF file. Just a wrapper for vdf.dumps. - """ - vdf.dump(data, fp, pretty=True) - - @staticmethod - def is_proton(path: str) -> bool: - """ - Checks if a directory is a Proton directory. - """ - toolmanifest = os.path.join(path, "toolmanifest.vdf") - if not os.path.isfile(toolmanifest): - return False - - f = open(toolmanifest, errors="replace") - data = SteamUtils.parse_vdf(f.read()) - compat_layer_name = data.get("manifest", {}).get("compatmanager_layer_name", {}) - - commandline = data.get("manifest", {}).get("commandline", {}) - - return "proton" in compat_layer_name or "proton" in commandline - - @staticmethod - def get_associated_runtime(path: str) -> str | None: - """ - Get the associated runtime of a Proton directory. - """ - toolmanifest = os.path.join(path, "toolmanifest.vdf") - if not os.path.isfile(toolmanifest): - logging.error(f"toolmanifest.vdf not found in Proton directory: {path}") - return None - - runtime = "scout" - f = open(toolmanifest, errors="replace") - data = SteamUtils.parse_vdf(f.read()) - tool_appid = data.get("manifest", {}).get("require_tool_appid", {}) - - if "1628350" in tool_appid: - runtime = "sniper" - elif "1391110" in tool_appid: - runtime = "soldier" - - return runtime - - @staticmethod - def get_dist_directory(path: str) -> str: - """ - Get the sub-directory containing the wine libraries and binaries. - """ - dist_directory = path - if os.path.isdir(os.path.join(path, "dist")): - dist_directory = os.path.join(path, "dist") - elif os.path.isdir(os.path.join(path, "files")): - dist_directory = os.path.join(path, "files") - else: - logging.warning( - f"No /dist or /files sub-directory was found under this Proton directory: {path}" - ) - - return dist_directory - - @staticmethod - def handle_launch_options(launch_options: str) -> tuple[str, str, dict[str, str]]: - """ - Handle launch options. Supports the %command% pattern. - Return prefix, arguments, and environment variables. - """ - env_vars = {} - prefix, args = "", "" - if "%command%" in launch_options: - _c = launch_options.split("%command%") - prefix = _c[0] if len(_c) > 0 else "" - args = _c[1] if len(_c) > 1 else "" - else: - args = launch_options - - try: - prefix_list = shlex.split(prefix.strip()) - except ValueError: - prefix_list = prefix.split(shlex.quote(prefix.strip())) - - for p in prefix_list.copy(): - if "=" in p: - k, v = p.split("=", 1) - v = shlex.quote(v) if " " in v else v - env_vars[k] = v - prefix_list.remove(p) - - prefix = " ".join(prefix_list) - return prefix, args, env_vars diff --git a/bottles/backend/wine/winecommand.py b/bottles/backend/wine/winecommand.py index 0237a532051..5a131946dec 100644 --- a/bottles/backend/wine/winecommand.py +++ b/bottles/backend/wine/winecommand.py @@ -21,7 +21,6 @@ from bottles.backend.utils.gpu import GPUUtils from bottles.backend.utils.manager import ManagerUtils from bottles.backend.utils.terminal import TerminalUtils -from bottles.backend.utils.steam import SteamUtils class WineEnv: @@ -173,13 +172,6 @@ def get_env( bottle = ManagerUtils.get_bottle_path(config) runner_path = ManagerUtils.get_runner_path(config.Runner) - if config.Environment == "Steam": - bottle = config.Path - runner_path = config.RunnerPath - - if SteamUtils.is_proton(runner_path): - runner_path = SteamUtils.get_dist_directory(runner_path) - # Clean some env variables which can cause trouble # ref: # env.remove("XDG_DATA_HOME") @@ -423,16 +415,7 @@ def _get_runner_info(self) -> tuple[str, str]: if runner in [None, ""]: return "", "" - if SteamUtils.is_proton(runner): - """ - If the runner is Proton, set the path to /dist or /files - based on check if files exists. - Additionally, check for its corresponding runtime. - """ - runner_runtime = SteamUtils.get_associated_runtime(runner) - runner = os.path.join(SteamUtils.get_dist_directory(runner), "bin/wine") - - elif runner.startswith("sys-"): + if runner.startswith("sys-"): """ If the runner type is system, set the runner binary path to the system command. Else set it to the full path. @@ -512,24 +495,6 @@ def get_cmd( if obs_vkc_available and params.obsvkc: command = f"{obs_vkc_available} {command}" - if self.arguments: - prefix, suffix, extracted_env = SteamUtils.handle_launch_options( - self.arguments - ) - if prefix: - command = f"{prefix} {command}" - if suffix: - command = f"{command} {suffix}" - if extracted_env: - if extracted_env.get("WINEDLLOVERRIDES") and environment.get( - "WINEDLLOVERRIDES" - ): - environment["WINEDLLOVERRIDES"] += ";" + extracted_env.get( - "WINEDLLOVERRIDES" - ) - del extracted_env["WINEDLLOVERRIDES"] - environment.update(extracted_env) - if post_script not in (None, ""): command = f"{command} ; sh '{post_script}'" diff --git a/bottles/backend/wine/wineserver.py b/bottles/backend/wine/wineserver.py index 37bb8a96ba4..0618db98e6c 100644 --- a/bottles/backend/wine/wineserver.py +++ b/bottles/backend/wine/wineserver.py @@ -4,7 +4,6 @@ from bottles.backend.utils.manager import ManagerUtils from bottles.backend.utils.proc import ProcUtils -from bottles.backend.utils.steam import SteamUtils from bottles.backend.wine.wineprogram import WineProgram @@ -28,13 +27,6 @@ def is_alive(self): bottle = ManagerUtils.get_bottle_path(config) runner = ManagerUtils.get_runner_path(config.Runner) - if config.Environment == "Steam": - bottle = config.Path - runner = config.RunnerPath - - if SteamUtils.is_proton(runner): - runner = SteamUtils.get_dist_directory(runner) - env = os.environ.copy() env["WINEPREFIX"] = bottle env["PATH"] = f"{runner}/bin:{env['PATH']}" @@ -57,13 +49,6 @@ def wait(self): bottle = ManagerUtils.get_bottle_path(config) runner = ManagerUtils.get_runner_path(config.Runner) - if config.Environment == "Steam": - bottle = config.Path - runner = config.RunnerPath - - if SteamUtils.is_proton(runner): - runner = SteamUtils.get_dist_directory(runner) - env = os.environ.copy() env["WINEPREFIX"] = bottle env["PATH"] = f"{runner}/bin:{env['PATH']}" From 6c5406ca28660f50428eff6f86eeeae75736c7c2 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Tue, 4 Feb 2025 21:03:20 -0500 Subject: [PATCH 133/146] backend: Remove leftover Steam --- bottles/backend/wine/winecommand.py | 132 +++++++++++----------------- 1 file changed, 52 insertions(+), 80 deletions(-) diff --git a/bottles/backend/wine/winecommand.py b/bottles/backend/wine/winecommand.py index 5a131946dec..ededb30dda2 100644 --- a/bottles/backend/wine/winecommand.py +++ b/bottles/backend/wine/winecommand.py @@ -129,10 +129,7 @@ def _get_config(self, config: BottleConfig) -> BottleConfig: def _get_cwd(self, cwd) -> str: config = self.config - if config.Environment == "Steam": - bottle = config.Path - else: - bottle = ManagerUtils.get_bottle_path(config) + bottle = ManagerUtils.get_bottle_path(config) if not cwd: """ @@ -152,10 +149,8 @@ def _get_cwd(self, cwd) -> str: def get_env( self, environment: dict | None = None, - return_steam_env: bool = False, - return_clean_env: bool = False, ) -> dict: - env = WineEnv(clean=return_steam_env or return_clean_env) + env = WineEnv() config = self.config arch = config.Arch params = config.Parameters @@ -208,8 +203,7 @@ def get_env( dll_overrides.append(f"{k}={v}") # Default DLL overrides - if not return_steam_env: - dll_overrides.append("winemenubuilder=''") + dll_overrides.append("winemenubuilder=''") # Get Runner libraries if arch == "win64": @@ -243,7 +237,7 @@ def get_env( ld.append(_path) # Embedded GStreamer environment variables - if not env.has("BOTTLES_USE_SYSTEM_GSTREAMER") and not return_steam_env: + if not env.has("BOTTLES_USE_SYSTEM_GSTREAMER"): gst_env_path = [] for lib in gst_libs: if os.path.exists(os.path.join(runner_path, lib)): @@ -252,7 +246,7 @@ def get_env( env.add("GST_PLUGIN_SYSTEM_PATH", ":".join(gst_env_path), override=True) # DXVK environment variables - if params.dxvk and not return_steam_env: + if params.dxvk: env.add("WINE_LARGE_ADDRESS_AWARE", "1") env.add( "DXVK_STATE_CACHE_PATH", os.path.join(bottle, "cache", "dxvk_state") @@ -271,13 +265,13 @@ def get_env( ) # VKD3D environment variables - if params.vkd3d and not return_steam_env: + if params.vkd3d: env.add( "VKD3D_SHADER_CACHE_PATH", os.path.join(bottle, "cache", "vkd3d_shader") ) # LatencyFleX environment variables - if params.latencyflex and not return_steam_env: + if params.latencyflex: _lf_path = ManagerUtils.get_latencyflex_path(config.LatencyFleX) _lf_layer_path = os.path.join( _lf_path, "layer/usr/share/vulkan/implicit_layer.d" @@ -315,7 +309,7 @@ def get_env( env.add("OBS_USE_EGL", "1") # DXVK-Nvapi environment variables - if params.dxvk_nvapi and not return_steam_env: + if params.dxvk_nvapi: # NOTE: users reported that DXVK_ENABLE_NVAPI and DXVK_NVAPIHACK must be set to make # DLSS works. I don't have a GPU compatible with this tech, so I'll trust them env.add("DXVK_NVAPIHACK", "0") @@ -330,11 +324,10 @@ def get_env( env.add("WINEFSYNC", "1") # Wine debug level - if not return_steam_env: - debug_level = "fixme-all" - if params.fixme_logs: - debug_level = "+fixme-all" - env.add("WINEDEBUG", debug_level) + debug_level = "fixme-all" + if params.fixme_logs: + debug_level = "+fixme-all" + env.add("WINEDEBUG", debug_level) # Aco compiler # if params["aco_compiler"]: @@ -352,39 +345,38 @@ def get_env( env.add("PULSE_LATENCY_MSEC", "60") # Discrete GPU - if not return_steam_env: - if params.discrete_gpu: - discrete = gpu["prime"]["discrete"] - if discrete is not None: - gpu_envs = discrete["envs"] - for p in gpu_envs: - env.add(p, gpu_envs[p]) - env.concat("VK_ICD_FILENAMES", discrete["icd"]) - - # VK_ICD - if not env.has("VK_ICD_FILENAMES"): - if gpu["prime"]["integrated"] is not None: - """ - System support PRIME but user disabled the discrete GPU - setting (previus check skipped), so using the integrated one. - """ - env.concat("VK_ICD_FILENAMES", gpu["prime"]["integrated"]["icd"]) + if params.discrete_gpu: + discrete = gpu["prime"]["discrete"] + if discrete is not None: + gpu_envs = discrete["envs"] + for p in gpu_envs: + env.add(p, gpu_envs[p]) + env.concat("VK_ICD_FILENAMES", discrete["icd"]) + + # VK_ICD + if not env.has("VK_ICD_FILENAMES"): + if gpu["prime"]["integrated"] is not None: + """ + System support PRIME but user disabled the discrete GPU + setting (previus check skipped), so using the integrated one. + """ + env.concat("VK_ICD_FILENAMES", gpu["prime"]["integrated"]["icd"]) + else: + """ + System doesn't support PRIME, so using the first result + from the gpu vendors list. + """ + if "vendors" in gpu and len(gpu["vendors"]) > 0: + _first = list(gpu["vendors"].keys())[0] + env.concat("VK_ICD_FILENAMES", gpu["vendors"][_first]["icd"]) else: - """ - System doesn't support PRIME, so using the first result - from the gpu vendors list. - """ - if "vendors" in gpu and len(gpu["vendors"]) > 0: - _first = list(gpu["vendors"].keys())[0] - env.concat("VK_ICD_FILENAMES", gpu["vendors"][_first]["icd"]) - else: - logging.warning( - "No GPU vendor found, keep going without setting VK_ICD_FILENAMES…" - ) - - # Add ld to LD_LIBRARY_PATH - if ld: - env.concat("LD_LIBRARY_PATH", ld) + logging.warning( + "No GPU vendor found, keep going without setting VK_ICD_FILENAMES…" + ) + + # Add ld to LD_LIBRARY_PATH + if ld: + env.concat("LD_LIBRARY_PATH", ld) # Vblank # env.add("__GL_SYNC_TO_VBLANK", "0") @@ -395,11 +387,10 @@ def get_env( if env.is_empty("WINEDLLOVERRIDES"): env.remove("WINEDLLOVERRIDES") - if not return_steam_env: - # Wine prefix - env.add("WINEPREFIX", bottle, override=True) - # Wine arch - env.add("WINEARCH", arch) + # Wine prefix + env.add("WINEPREFIX", bottle, override=True) + # Wine arch + env.add("WINEARCH", arch) return env.get()["envs"] @@ -409,9 +400,6 @@ def _get_runner_info(self) -> tuple[str, str]: arch = config.Arch runner_runtime = "" - if config.Environment == "Steam": - runner = config.RunnerPath - if runner in [None, ""]: return "", "" @@ -438,8 +426,6 @@ def get_cmd( pre_script: str | None = None, post_script: str | None = None, midi_soundfont: str | None = None, - return_steam_cmd: bool = False, - return_clean_cmd: bool = False, environment: dict | None = None, ) -> str: config = self.config @@ -449,24 +435,14 @@ def get_cmd( if environment is None: environment = {} - if return_clean_cmd: - return_steam_cmd = True - - if not return_steam_cmd and not return_clean_cmd: - command = f"{runner} {command}" + command = f"{runner} {command}" if not self.minimal: if gamemode_available and params.gamemode: - if not return_steam_cmd: - command = f"{gamemode_available} {command}" - else: - command = f"gamemode {command}" + command = f"{gamemode_available} {command}" if mangohud_available and params.mangohud and not self.gamescope_activated: - if not return_steam_cmd: - command = f"{mangohud_available} {command}" - else: - command = f"mangohud {command}" + command = f"{mangohud_available} {command}" if gamescope_available and self.gamescope_activated: gamescope_run = tempfile.NamedTemporaryFile(mode="w", suffix=".sh").name @@ -480,9 +456,7 @@ def get_cmd( f.write("".join(file)) # Update command - command = ( - f"{self._get_gamescope_cmd(return_steam_cmd)} -- {gamescope_run}" - ) + command = f"{self._get_gamescope_cmd()} -- {gamescope_run}" logging.info(f"Running Gamescope command: '{command}'") logging.info(f"{gamescope_run} contains:") with open(gamescope_run) as f: @@ -503,15 +477,13 @@ def get_cmd( return command - def _get_gamescope_cmd(self, return_steam_cmd: bool = False) -> str: + def _get_gamescope_cmd(self) -> str: config = self.config params = config.Parameters gamescope_cmd = [] if gamescope_available and self.gamescope_activated: gamescope_cmd = [gamescope_available] - if return_steam_cmd: - gamescope_cmd = ["gamescope"] if params.gamescope_fullscreen: gamescope_cmd.append("-f") if params.gamescope_borderless: From 6474b001f1b9794fa501d8323928c79652159132 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Tue, 4 Feb 2025 22:13:48 -0500 Subject: [PATCH 134/146] frontend: Remove MIDI SoundFont --- bottles/frontend/filters.py | 4 -- bottles/frontend/launch-options-dialog.blp | 31 ------------- bottles/frontend/launch_options_dialog.py | 52 ---------------------- 3 files changed, 87 deletions(-) diff --git a/bottles/frontend/filters.py b/bottles/frontend/filters.py index 58b19690371..509bd850e0b 100644 --- a/bottles/frontend/filters.py +++ b/bottles/frontend/filters.py @@ -27,10 +27,6 @@ def add_executable_filters(dialog): __set_filter(dialog, _("Supported Executables"), ["*.exe", "*.msi"]) -def add_soundfont_filters(dialog): - __set_filter(dialog, _("Supported SoundFonts"), ["*.sf2", "*.sf3"]) - - def add_yaml_filters(dialog): # TODO: Investigate why `filter.add_mime_type(...)` does not show filter in all distributions. # Intended MIME types are: diff --git a/bottles/frontend/launch-options-dialog.blp b/bottles/frontend/launch-options-dialog.blp index e107cab0221..ebd35d227ec 100644 --- a/bottles/frontend/launch-options-dialog.blp +++ b/bottles/frontend/launch-options-dialog.blp @@ -140,37 +140,6 @@ template $LaunchOptionsDialog: Adw.Window { } } } - - Adw.ActionRow action_midi_soundfont { - activatable-widget: btn_midi_soundfont; - title: _("MIDI SoundFont"); - subtitle: _("Choose a custom SoundFont for MIDI playback."); - - Box { - spacing: 6; - - Button btn_midi_soundfont_reset { - tooltip-text: _("Reset to Default"); - valign: center; - visible: false; - icon-name: "edit-undo-symbolic"; - - styles [ - "flat", - ] - } - - Button btn_midi_soundfont { - tooltip-text: _("Choose a SoundFont"); - valign: center; - icon-name: "document-open-symbolic"; - - styles [ - "flat", - ] - } - } - } } Adw.PreferencesGroup { diff --git a/bottles/frontend/launch_options_dialog.py b/bottles/frontend/launch_options_dialog.py index 0cba23b813f..4e3e7e2123f 100644 --- a/bottles/frontend/launch_options_dialog.py +++ b/bottles/frontend/launch_options_dialog.py @@ -19,7 +19,6 @@ from bottles.backend.utils.manager import ManagerUtils import logging -from bottles.frontend.filters import add_all_filters, add_soundfont_filters from gettext import gettext as _ @@ -39,12 +38,9 @@ class LaunchOptionsDialog(Adw.Window): btn_post_script_reset = Gtk.Template.Child() btn_cwd = Gtk.Template.Child() btn_cwd_reset = Gtk.Template.Child() - btn_midi_soundfont = Gtk.Template.Child() - btn_midi_soundfont_reset = Gtk.Template.Child() btn_reset_defaults = Gtk.Template.Child() action_pre_script = Gtk.Template.Child() action_post_script = Gtk.Template.Child() - action_midi_soundfont = Gtk.Template.Child() switch_dxvk = Gtk.Template.Child() switch_vkd3d = Gtk.Template.Child() switch_nvapi = Gtk.Template.Child() @@ -63,7 +59,6 @@ class LaunchOptionsDialog(Adw.Window): __default_pre_script_msg = _("Choose a script which should be executed before run.") __default_post_script_msg = _("Choose a script which should be executed after run.") __default_cwd_msg = _("Choose from where start the program.") - __default_midi_soundfont_msg = _("Choose a custom SoundFont for MIDI playback.") __msg_disabled = _("{0} is disabled globally for this bottle.") __msg_override = _("This setting overrides the bottle's global setting.") @@ -109,8 +104,6 @@ def __init__(self, parent, config, program, **kwargs): self.btn_pre_script_reset.connect("clicked", self.__reset_pre_script) self.btn_post_script.connect("clicked", self.__choose_post_script) self.btn_post_script_reset.connect("clicked", self.__reset_post_script) - self.btn_midi_soundfont.connect("clicked", self.__choose_midi_soundfont) - self.btn_midi_soundfont_reset.connect("clicked", self.__reset_midi_soundfont) self.btn_cwd.connect("clicked", self.__choose_cwd) self.btn_cwd_reset.connect("clicked", self.__reset_cwd) self.btn_reset_defaults.connect("clicked", self.__reset_defaults) @@ -190,10 +183,6 @@ def __init__(self, parent, config, program, **kwargs): self.action_cwd.set_subtitle(program["folder"]) self.btn_cwd_reset.set_visible(True) - if program.get("midi_soundfont") not in ["", None]: - self.action_midi_soundfont.set_subtitle(program["midi_soundfont"]) - self.btn_midi_soundfont_reset.set_visible(True) - self.__set_disabled_switches() def __check_override(self, widget, state, action, name): @@ -353,47 +342,6 @@ def __reset_cwd(self, *_args): self.action_cwd.set_subtitle(self.__default_cwd_msg) self.btn_cwd_reset.set_visible(False) - def __choose_midi_soundfont(self, *_args): - def set_path(dialog, result): - try: - file = dialog.open_finish(result) - if file is None: - self.action_midi_soundfont.set_subtitle( - self.__default_midi_soundfont_msg - ) - return - - file_path = file.get_path() - self.program["midi_soundfont"] = file_path - self.action_midi_soundfont.set_subtitle(file_path) - self.btn_midi_soundfont_reset.set_visible(True) - - except GLib.Error as error: - # also thrown when dialog has been cancelled - if error.code == 2: - # error 2 seems to be 'dismiss' or 'cancel' - if self.program["midi_soundfont"] in (None, ""): - self.action_midi_soundfont.set_subtitle( - self.__default_midi_soundfont_msg - ) - else: - # something else happened... - logging.warning("Error selecting SoundFont file: %s" % error) - - dialog = Gtk.FileDialog.new() - dialog.set_title(_("Select MIDI SoundFont")) - dialog.set_modal(True) - - add_soundfont_filters(dialog) - add_all_filters(dialog) - - dialog.open(parent=self.window, callback=set_path) - - def __reset_midi_soundfont(self, *_args): - self.program["midi_soundfont"] = None - self.action_midi_soundfont.set_subtitle(self.__default_midi_soundfont_msg) - self.btn_midi_soundfont_reset.set_visible(False) - def __reset_defaults(self, *_args): self.switch_dxvk.set_active(self.global_dxvk) self.switch_vkd3d.set_active(self.global_vkd3d) From 465d18081ffd30fc0fcd822016491e12d0057ca1 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Tue, 4 Feb 2025 22:14:00 -0500 Subject: [PATCH 135/146] backend: Remove MIDI SoundFont --- bottles/backend/utils/meson.build | 1 - bottles/backend/utils/midi.py | 108 ------------------------------ bottles/backend/wine/executor.py | 13 ---- 3 files changed, 122 deletions(-) delete mode 100644 bottles/backend/utils/midi.py diff --git a/bottles/backend/utils/meson.build b/bottles/backend/utils/meson.build index e75e2f9916b..3d17a23ff1c 100644 --- a/bottles/backend/utils/meson.build +++ b/bottles/backend/utils/meson.build @@ -6,7 +6,6 @@ bottles_sources = [ 'display.py', 'gpu.py', 'manager.py', - 'midi.py', 'vulkan.py', 'terminal.py', 'file.py', diff --git a/bottles/backend/utils/midi.py b/bottles/backend/utils/midi.py deleted file mode 100644 index d80cfb4e4fe..00000000000 --- a/bottles/backend/utils/midi.py +++ /dev/null @@ -1,108 +0,0 @@ -# midi.py -# -# Copyright 2025 The Bottles Contributors -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, in version 3 of the License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from typing import Self - -from ctypes import c_void_p -from fluidsynth import cfunc, Synth # type: ignore [import-untyped] - -import logging -from bottles.backend.models.config import BottleConfig -from bottles.backend.wine.reg import Reg - - -class FluidSynth: - """FluidSynth instance bounded to a unique SoundFont (.sf2, .sf3) file.""" - - __active_instances: dict[int, Self] = {} - - @classmethod - def find_or_create(cls, soundfont_path: str) -> Self: - """ - Search for running FluidSynth instance and return it. - If nonexistent, create and add it to active ones beforehand. - """ - - for fs in cls.__active_instances.values(): - if fs.soundfont_path == soundfont_path: - fs.program_count += 1 - return fs - - fs = cls(soundfont_path) - cls.__active_instances[fs.id] = fs - return fs - - def __init__(self, soundfont_path: str): - """Build a new FluidSynth object from SoundFont file path.""" - self.soundfont_path = soundfont_path - self.id = self.__get_vacant_id() - self.__start() - self.program_count = 1 - - @classmethod - def __get_vacant_id(cls) -> int: - """Get smallest 0-indexed ID currently not in use by a SoundFont.""" - n = len(cls.__active_instances) - return next(i for i in range(n + 1) if i not in cls.__active_instances) - - def __start(self): - """Start FluidSynth synthetizer with loaded SoundFont.""" - logging.info( - "Starting new FluidSynth server with SoundFont" - f" #{self.id} ('{self.soundfont_path}')…" - ) - synth = Synth(channels=16) - synth.start() - sfid = synth.sfload(self.soundfont_path) - synth.program_select(0, sfid, 0, 0) - self.synth = synth - - def register_as_current(self, config: BottleConfig): - """ - Update Wine registry with this instance's ID, instructing - MIDI mapping to load the correct instrument set on program startup. - """ - reg = Reg(config) - reg.add( - key="HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Multimedia\\MIDIMap", - value="CurrentInstrument", - data=f"#{self.id}", - value_type="REG_SZ", - ) - - def decrement_program_counter(self): - """Decrement program counter; if it reaches zero, delete this instance.""" - self.program_count -= 1 - if self.program_count == 0: - self.__delete() - - def __delete(self): - """Kill underlying synthetizer and remove FluidSynth instance from dict.""" - - def __delete_synth(synth: Synth): - """Bind missing function and run deletion routines.""" - delete_fluid_midi_driver = cfunc( - "delete_fluid_midi_driver", c_void_p, ("driver", c_void_p, 1) - ) - delete_fluid_midi_driver(synth.midi_driver) - synth.delete() - - logging.info( - "Killing FluidSynth server with SoundFont" - f" #{self.id} ('{self.soundfont_path}')…" - ) - __delete_synth(self.synth) - self.__active_instances.pop(self.id) diff --git a/bottles/backend/wine/executor.py b/bottles/backend/wine/executor.py index d9554e27f1b..7af98bb95f6 100644 --- a/bottles/backend/wine/executor.py +++ b/bottles/backend/wine/executor.py @@ -9,7 +9,6 @@ from bottles.backend.models.config import BottleConfig from bottles.backend.models.result import Result from bottles.backend.utils.manager import ManagerUtils -from bottles.backend.utils.midi import FluidSynth from bottles.backend.wine.cmd import CMD from bottles.backend.wine.explorer import Explorer from bottles.backend.wine.msiexec import MsiExec @@ -69,13 +68,6 @@ def __init__( env_dll_overrides = [] - self.fluidsynth = None - if (soundfont_path := midi_soundfont) not in (None, ""): - # FluidSynth instance is bound to WineExecutor as a member to control - # the former's lifetime (deleted when no more references from executors) - self.fluidsynth = FluidSynth.find_or_create(soundfont_path) - self.fluidsynth.register_as_current(config) - # None = use global DXVK value if program_dxvk is not None: # DXVK is globally activated, but disabled for the program @@ -361,8 +353,3 @@ def __set_monitors(self): winedbg = WineDbg(self.config, silent=True) for m in self.monitoring: winedbg.wait_for_process(name=m) - - def __del__(self): - """On exit, kill FluidSynth instance if this was the last executor using it.""" - if self.fluidsynth: - self.fluidsynth.decrement_program_counter() From a1a2813e96afb415bec8b1f231376449b89de4fa Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Wed, 5 Feb 2025 09:10:14 -0500 Subject: [PATCH 136/146] backend: Remove hh --- bottles/backend/wine/hh.py | 6 ------ bottles/backend/wine/meson.build | 1 - 2 files changed, 7 deletions(-) delete mode 100644 bottles/backend/wine/hh.py diff --git a/bottles/backend/wine/hh.py b/bottles/backend/wine/hh.py deleted file mode 100644 index bc26d7bdfa1..00000000000 --- a/bottles/backend/wine/hh.py +++ /dev/null @@ -1,6 +0,0 @@ -from bottles.backend.wine.wineprogram import WineProgram - - -class Hh(WineProgram): - program = "Wine HTML help viewer" - command = "hh" diff --git a/bottles/backend/wine/meson.build b/bottles/backend/wine/meson.build index c707c904182..7b734db90b4 100644 --- a/bottles/backend/wine/meson.build +++ b/bottles/backend/wine/meson.build @@ -29,7 +29,6 @@ bottles_sources = [ 'drives.py', 'eject.py', 'expand.py', - 'hh.py', 'icinfo.py', 'notepad.py', 'oleview.py', From 7cb64ece57b5c3e1300e16ad4fc978d8a3c6b558 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Thu, 6 Feb 2025 22:28:38 -0500 Subject: [PATCH 137/146] frontend: Remove LoadingView --- bottles/frontend/bottles.gresource.xml | 1 - bottles/frontend/loading-view.blp | 45 -------------------- bottles/frontend/loading_view.py | 57 -------------------------- bottles/frontend/meson.build | 2 - bottles/frontend/window.py | 13 ------ 5 files changed, 118 deletions(-) delete mode 100644 bottles/frontend/loading-view.blp delete mode 100644 bottles/frontend/loading_view.py diff --git a/bottles/frontend/bottles.gresource.xml b/bottles/frontend/bottles.gresource.xml index d078011fbc6..67ee91433ae 100644 --- a/bottles/frontend/bottles.gresource.xml +++ b/bottles/frontend/bottles.gresource.xml @@ -7,7 +7,6 @@ window.ui new-bottle-dialog.ui bottles-list-view.ui - loading-view.ui bottle-row.ui check-row.ui task-row.ui diff --git a/bottles/frontend/loading-view.blp b/bottles/frontend/loading-view.blp deleted file mode 100644 index 5967a8d55e9..00000000000 --- a/bottles/frontend/loading-view.blp +++ /dev/null @@ -1,45 +0,0 @@ -using Gtk 4.0; -using Adw 1; - -template $LoadingView: Adw.Bin { - WindowHandle { - hexpand: true; - vexpand: true; - - Box { - orientation: vertical; - - Adw.StatusPage loading_status_page { - title: _("Starting up…"); - hexpand: true; - vexpand: true; - } - - Button btn_go_offline { - margin-bottom: 20; - valign: center; - halign: center; - label: _("Continue Offline"); - - styles [ - "destructive-action", - "pill", - ] - } - - Label label_fetched { - styles [ - "dim-label", - ] - } - - Label label_downloading { - margin-bottom: 20; - - styles [ - "dim-label", - ] - } - } - } -} diff --git a/bottles/frontend/loading_view.py b/bottles/frontend/loading_view.py deleted file mode 100644 index 330f26ac469..00000000000 --- a/bottles/frontend/loading_view.py +++ /dev/null @@ -1,57 +0,0 @@ -# loading_view.py -# -# Copyright 2025 The Bottles Contributors -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, in version 3 of the License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# - -from gettext import gettext as _ - -from gi.repository import Gtk, Adw - -from bottles.backend.models.result import Result -from bottles.backend.state import SignalManager, Signals -from bottles.frontend.gtk import GtkUtils -from bottles.frontend.params import APP_ID - - -@Gtk.Template(resource_path="/com/usebottles/bottles/loading-view.ui") -class LoadingView(Adw.Bin): - __gtype_name__ = "LoadingView" - __fetched = 0 - - # region widgets - label_fetched = Gtk.Template.Child() - label_downloading = Gtk.Template.Child() - btn_go_offline = Gtk.Template.Child() - loading_status_page = Gtk.Template.Child() - # endregion - - def __init__(self, **kwargs): - super().__init__(**kwargs) - self.loading_status_page.set_icon_name(APP_ID) - self.btn_go_offline.connect("clicked", self.go_offline) - - @GtkUtils.run_in_main_loop - def add_fetched(self, res: Result): - total: int = res.data - self.__fetched += 1 - self.label_downloading.set_text( - _("Downloading ~{0} of packages…").format("20kb") - ) - self.label_fetched.set_text( - _("Fetched {0} of {1} packages").format(self.__fetched, total) - ) - - def go_offline(self, _widget): - SignalManager.send(Signals.ForceStopNetworking, Result(status=True)) diff --git a/bottles/frontend/meson.build b/bottles/frontend/meson.build index cd08cb04674..0dcbce59083 100644 --- a/bottles/frontend/meson.build +++ b/bottles/frontend/meson.build @@ -38,7 +38,6 @@ blueprints = custom_target('blueprints', 'env-var-entry.blp', 'bottle-row.blp', 'bottles-list-view.blp', - 'loading-view.blp', 'local-resource-row.blp', 'new-bottle-dialog.blp', 'onboard-dialog.blp', @@ -87,7 +86,6 @@ bottles_sources = [ 'bottles_list_view.py', 'bottle_details_view.py', 'preferences.py', - 'loading_view.py', 'bottle_details_page.py', 'details_dependencies_view.py', 'details_preferences_page.py', diff --git a/bottles/frontend/window.py b/bottles/frontend/window.py index ca84771c85f..1dc275a9608 100644 --- a/bottles/frontend/window.py +++ b/bottles/frontend/window.py @@ -35,7 +35,6 @@ from bottles.frontend.gtk import GtkUtils from bottles.frontend.bottle_details_view import BottleDetailsView from bottles.frontend.bottles_list_view import BottlesListView -from bottles.frontend.loading_view import LoadingView from bottles.frontend.new_bottle_dialog import NewBottleDialog from bottles.frontend.preferences import PreferencesWindow from bottles.frontend.crash_report_dialog import CrashReportDialog @@ -116,13 +115,6 @@ def response(dialog, response, *args): logging.error("https://usebottles.com/download/") return - # Loading view - self.page_loading = LoadingView() - - # Populate stack - self.stack_main.add_named( - child=self.page_loading, name="page_loading" - ).set_visible(False) self.headerbar.add_css_class("flat") # Signal connections @@ -239,7 +231,6 @@ def get_manager(): mng = Manager(g_settings=self.settings) return mng - self.show_loading_view() RunAsync(get_manager, callback=set_manager) self.check_crash_log() @@ -267,10 +258,6 @@ def show_details_view(self, widget=False, config: BottleConfig | None = None): self.main_leaf.set_visible_child(self.page_details) self.page_details.set_config(config or BottleConfig()) - def show_loading_view(self, widget=False): - self.lock_ui() - self.stack_main.set_visible_child_name("page_loading") - def show_onboard_view(self, widget=False): onboard_window = OnboardDialog(self) onboard_window.present() From fc95d0daab3992b6bf726df53aeec180d7c0ef34 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Sat, 8 Feb 2025 12:49:18 -0500 Subject: [PATCH 138/146] main: Remove unnecessary locale variables --- bottles/frontend/main.py | 39 +-------------------------------------- 1 file changed, 1 insertion(+), 38 deletions(-) diff --git a/bottles/frontend/main.py b/bottles/frontend/main.py index a2cdb82bf63..3d5b2c25368 100644 --- a/bottles/frontend/main.py +++ b/bottles/frontend/main.py @@ -17,10 +17,8 @@ import sys import gi -import gettext -import locale import webbrowser -from os import path +from gettext import gettext as _ import logging from bottles.backend.health import HealthChecker @@ -43,41 +41,6 @@ from bottles.frontend.preferences import PreferencesWindow -# region Translations -""" -This code snippet searches for and uploads translations to different -directories, depending on your production or development environment. -The function _() can be used to create and retrieve translations. -""" -share_dir = path.join(sys.prefix, "share") -base_dir = "." - -if getattr(sys, "frozen", False): - base_dir = path.dirname(sys.executable) - share_dir = path.join(base_dir, "share") -elif sys.argv[0]: - exec_dir = path.dirname(path.realpath(sys.argv[0])) - base_dir = path.dirname(exec_dir) - share_dir = path.join(base_dir, "share") - - if not path.exists(share_dir): - share_dir = base_dir - -locale_dir = path.join(share_dir, "locale") - -if not path.exists(locale_dir): # development - locale_dir = path.join(base_dir, "build", "mo") - -locale.bindtextdomain("bottles", locale_dir) -locale.textdomain("bottles") -gettext.bindtextdomain("bottles", locale_dir) -gettext.textdomain("bottles") -_ = gettext.gettext - - -# endregion - - class Bottles(Adw.Application): arg_exe = None arg_bottle = None From 11d7671fd2806f6d82e62b9ad3190f85cfd33441 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Sun, 9 Feb 2025 09:28:49 -0500 Subject: [PATCH 139/146] backend: Initial Bottle class --- bottles/backend/bottle.py | 57 +++++++++++++++++++++++++++++++++++++ bottles/backend/meson.build | 1 + 2 files changed, 58 insertions(+) create mode 100644 bottles/backend/bottle.py diff --git a/bottles/backend/bottle.py b/bottles/backend/bottle.py new file mode 100644 index 00000000000..6fbb044d036 --- /dev/null +++ b/bottles/backend/bottle.py @@ -0,0 +1,57 @@ +# bottle.py +# +# Copyright 2025 The Bottles Contributors +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, in version 3 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import os +import yaml + +from typing import cast + +from bottles.backend.models.config import BottleConfig + + +class Bottle: + """Class representing a bottle.""" + + @staticmethod + def generate_local_bottles_list(bottles_dir: str) -> dict[str, BottleConfig]: + """Generate a list of local bottles.""" + + local_bottles = {} + local_bottles_list = os.listdir(bottles_dir) + + for local_bottle in local_bottles_list: + local_bottle_dir = os.path.join(bottles_dir, local_bottle) + bottle_config_file_path = os.path.join(local_bottle_dir, "bottle.yml") + placeholder_file_path = os.path.join(local_bottle_dir, "placeholder.yml") + + try: + with open(placeholder_file_path) as file: + configuration = yaml.safe_load(file) + bottle_config_file_path = configuration["Path"] + except FileNotFoundError: + pass + + if not os.path.isfile(bottle_config_file_path): + continue + + config_load = BottleConfig.load(bottle_config_file_path) + + if not config_load.status: + raise TypeError(f"Unable to load {bottle_config_file_path}") + + local_bottles[local_bottle] = cast(BottleConfig, config_load.data) + + return local_bottles diff --git a/bottles/backend/meson.build b/bottles/backend/meson.build index 5bc3697a351..b65b506524b 100644 --- a/bottles/backend/meson.build +++ b/bottles/backend/meson.build @@ -16,6 +16,7 @@ subdir('managers') bottles_sources = [ '__init__.py', + 'bottle.py', 'globals.py', 'runner.py', 'diff.py', From eb72eb09fbd7b038fd12bab4850f327dad6324dc Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Sun, 9 Feb 2025 13:32:28 -0500 Subject: [PATCH 140/146] backend: Improve typing for BottleConfig --- bottles/backend/bottle.py | 4 +--- bottles/backend/models/config.py | 6 +++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/bottles/backend/bottle.py b/bottles/backend/bottle.py index 6fbb044d036..7aa8771cd73 100644 --- a/bottles/backend/bottle.py +++ b/bottles/backend/bottle.py @@ -17,8 +17,6 @@ import os import yaml -from typing import cast - from bottles.backend.models.config import BottleConfig @@ -52,6 +50,6 @@ def generate_local_bottles_list(bottles_dir: str) -> dict[str, BottleConfig]: if not config_load.status: raise TypeError(f"Unable to load {bottle_config_file_path}") - local_bottles[local_bottle] = cast(BottleConfig, config_load.data) + local_bottles[local_bottle] = config_load.data return local_bottles diff --git a/bottles/backend/models/config.py b/bottles/backend/models/config.py index 9136f027ae2..01882202aaf 100644 --- a/bottles/backend/models/config.py +++ b/bottles/backend/models/config.py @@ -3,7 +3,7 @@ import os from dataclasses import dataclass, field, replace, asdict, is_dataclass from io import IOBase -from typing import Optional, IO +from typing import IO, Self from collections.abc import ItemsView, Container from bottles.backend.models.result import Result @@ -170,7 +170,7 @@ def dump(self, file: str | IO, mode="w", encoding=None, indent=4) -> Result: f.close() @classmethod - def load(cls, file: str | IO, mode="r") -> Result[Optional["BottleConfig"]]: + def load(cls, file: str | IO, mode="r") -> Result[Self]: """ Load config from file @@ -204,7 +204,7 @@ def load(cls, file: str | IO, mode="r") -> Result[Optional["BottleConfig"]]: f.close() @classmethod - def _fill_with(cls, data: dict) -> Result[Optional["BottleConfig"]]: + def _fill_with(cls, data: dict) -> Result[Self | None]: """fill with dict""" try: data = data.copy() From 4d8ef2b9cd7d789c503e438d35b3df65fb804486 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Sun, 9 Feb 2025 09:29:18 -0500 Subject: [PATCH 141/146] frontend: Use Bottle class --- bottles/frontend/bottles_list_view.py | 31 +++++++------------- bottles/frontend/details_preferences_page.py | 1 - bottles/frontend/main.py | 7 +++++ bottles/frontend/window.py | 2 +- 4 files changed, 19 insertions(+), 22 deletions(-) diff --git a/bottles/frontend/bottles_list_view.py b/bottles/frontend/bottles_list_view.py index 6b960392e8c..27a8025b52b 100644 --- a/bottles/frontend/bottles_list_view.py +++ b/bottles/frontend/bottles_list_view.py @@ -25,6 +25,7 @@ from bottles.backend.state import Signals, SignalManager from bottles.backend.utils.threading import RunAsync from bottles.backend.wine.executor import WineExecutor +from bottles.frontend.gtk import GtkUtils from bottles.frontend.filters import add_executable_filters, add_all_filters from bottles.frontend.params import APP_ID @@ -41,12 +42,11 @@ class BottleRow(Adw.ActionRow): # endregion - def __init__(self, window, config: BottleConfig, **kwargs): + def __init__(self, config: BottleConfig, **kwargs): super().__init__(**kwargs) # common variables and references - self.window = window - self.manager = window.manager + self.window = GtkUtils.get_parent_window() self.config = config # Format update date @@ -140,21 +140,16 @@ class BottlesListView(Adw.Bin): # endregion - def __init__(self, window, **kwargs): + def __init__(self, **kwargs): super().__init__(**kwargs) # common variables and references - self.window = window + self.window = GtkUtils.get_parent_window() # connect signals self.btn_create.connect("clicked", self.window.show_add_view) self.entry_search.connect("changed", self.__search_bottles) - # backend signals - SignalManager.connect( - Signals.ManagerLocalBottlesLoaded, self.update_bottles_list - ) - self.bottle_status.set_icon_name(APP_ID) self.update_bottles_list() @@ -173,25 +168,21 @@ def __filter_bottles(row, terms=None): return terms.lower() in text def update_bottles_list(self, *args) -> None: - self.__bottles = {} + application = self.window.get_application() while self.list_bottles.get_first_child(): self.list_bottles.remove(self.list_bottles.get_first_child()) - local_bottles = self.window.manager.local_bottles - is_empty_local_bottles = len(local_bottles) == 0 + is_empty_local_bottles = len(application.local_bottles) == 0 self.pref_page.set_visible(not is_empty_local_bottles) self.bottle_status.set_visible(is_empty_local_bottles) - for name, config in local_bottles.items(): - _entry = BottleRow(self.window, config) - self.__bottles[config.Path] = _entry + for name, config in application.local_bottles.items(): + _entry = BottleRow(config) self.list_bottles.append(_entry) def show_page(self, page: str) -> None: - if config := self.window.manager.local_bottles.get(page): + application = self.window.get_application() + if config := application.local_bottles.get(page): self.window.show_details_view(config=config) - - def disable_bottle(self, config): - self.__bottles[config.Path].disable() diff --git a/bottles/frontend/details_preferences_page.py b/bottles/frontend/details_preferences_page.py index d5b5e17c794..b85fae43f76 100644 --- a/bottles/frontend/details_preferences_page.py +++ b/bottles/frontend/details_preferences_page.py @@ -277,7 +277,6 @@ def __save_name(self, *_args): self.manager.update_config(config=self.config, key="Name", value=new_name) - self.manager.update_bottles(silent=True) # Updates backend bottles list and UI self.window.page_library.update() self.details.view_bottle.label_name.set_text(self.config.Name) diff --git a/bottles/frontend/main.py b/bottles/frontend/main.py index 3d5b2c25368..80ed25c2cd9 100644 --- a/bottles/frontend/main.py +++ b/bottles/frontend/main.py @@ -15,6 +15,7 @@ # along with this program. If not, see . # +import os import sys import gi import webbrowser @@ -22,6 +23,7 @@ import logging from bottles.backend.health import HealthChecker +from bottles.backend.models.config import BottleConfig from bottles.frontend.params import ( APP_ID, APP_MAJOR_VERSION, @@ -38,6 +40,7 @@ # ruff: noqa: E402 from gi.repository import Gio, GLib, GObject, Adw # type: ignore from bottles.frontend.window import BottlesWindow +from bottles.backend.bottle import Bottle from bottles.frontend.preferences import PreferencesWindow @@ -45,6 +48,8 @@ class Bottles(Adw.Application): arg_exe = None arg_bottle = None dark_provider = None + local_bottles: dict[str, BottleConfig] = {} + bottles_config_dir = os.path.join(GLib.get_user_data_dir(), "bottles", "bottles") def __init__(self): super().__init__( @@ -61,6 +66,8 @@ def __init__(self): self.__register_arguments() + self.local_bottles = Bottle.generate_local_bottles_list(self.bottles_config_dir) + def __register_arguments(self): """ This function registers the command line arguments. diff --git a/bottles/frontend/window.py b/bottles/frontend/window.py index 1dc275a9608..f0a434b4453 100644 --- a/bottles/frontend/window.py +++ b/bottles/frontend/window.py @@ -190,7 +190,7 @@ def set_manager(result: Manager, error=None): # Pages self.page_details = BottleDetailsView(self) - self.page_list = BottlesListView(self) + self.page_list = BottlesListView() self.main_leaf.append(self.page_details) From ab66a29914eac924e7b2e212061b4acbaed1c756 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Sun, 9 Feb 2025 09:31:19 -0500 Subject: [PATCH 142/146] manager: Remove update methods --- bottles/backend/managers/manager.py | 157 ---------------------------- bottles/frontend/main.py | 10 -- 2 files changed, 167 deletions(-) diff --git a/bottles/backend/managers/manager.py b/bottles/backend/managers/manager.py index e2c98485f60..be62edee099 100644 --- a/bottles/backend/managers/manager.py +++ b/bottles/backend/managers/manager.py @@ -143,16 +143,8 @@ def checks(self, install_latest=False, first_run=False) -> Result: self.check_runners(install_latest) or rv.set_status(False) rv.data["check_runners"] = time.time() - self.check_bottles() - rv.data["check_bottles"] = time.time() - return rv - def update_bottles(self, silent: bool = False): - """Checks for new bottles and update the list view.""" - self.check_bottles(silent) - SignalManager.send(Signals.ManagerLocalBottlesLoaded) - def check_app_dirs(self): """ Checks for the existence of the bottles' directories, and creates them @@ -550,152 +542,6 @@ def get_programs(self, config: BottleConfig) -> list[dict]: return installed_programs - def check_bottles(self, silent: bool = False): - """ - Check for local bottles and update the local_bottles list. - Will also mark the broken ones if the configuration file is missing - """ - bottles = os.listdir(Paths.bottles) - - # Empty local bottles - self.local_bottles = {} - - def process_bottle(bottle): - _name = bottle - _bottle = str(os.path.join(Paths.bottles, bottle)) - _placeholder = os.path.join(_bottle, "placeholder.yml") - _config = os.path.join(_bottle, "bottle.yml") - - if os.path.exists(_placeholder): - with open(_placeholder) as f: - try: - placeholder_yaml = yaml.load(f) - if placeholder_yaml.get("Path"): - _config = os.path.join( - placeholder_yaml.get("Path"), "bottle.yml" - ) - else: - raise ValueError("Missing Path in placeholder.yml") - except (yaml.YAMLError, ValueError): - return - - config_load = BottleConfig.load(_config) - - if not config_load.status: - return - - config = config_load.data - - # Clear Run Executable parameters on new session start - if config.session_arguments: - config.session_arguments = "" - - if config.run_in_terminal: - config.run_in_terminal = False - - # Check if the path in the bottle config corresponds to the folder name - # if not, change the config to reflect the folder name - # if the folder name is "illegal" across all platforms, rename the folder - - # "universal" platform works for all filesystem/OSes - sane_name = pathvalidate.sanitize_filepath(_name, platform="universal") - if config.Custom_Path is False: # There shouldn't be problems with this - if config.Path != _name or sane_name != _name: - logging.warning( - 'Illegal bottle folder or mismatch between config "Path" and folder name' - ) - if sane_name != _name: - # This hopefully doesn't happen, but it's managed - logging.warning(f"Broken path in bottle {_name}, fixing...") - shutil.move( - _bottle, str(os.path.join(Paths.bottles, sane_name)) - ) - # Restart the process bottle function. Normally, can't be recursive! - process_bottle(sane_name) - return - - config.Path = sane_name - self.update_config(config=config, key="Path", value=sane_name) - - sample = BottleConfig() - miss_keys = sample.keys() - config.keys() - for key in miss_keys: - logging.warning(f"Key {key} is missing for bottle {_name}, updating…") - self.update_config(config=config, key=key, value=sample[key]) - - miss_params_keys = sample.Parameters.keys() - config.Parameters.keys() - - for key in miss_params_keys: - """ - For each missing key in the bottle configuration, set - it to the default value. - """ - logging.warning( - f"Parameters key {key} is missing for bottle {_name}, updating…" - ) - self.update_config( - config=config, - key=key, - value=sample.Parameters[key], - scope="Parameters", - ) - self.local_bottles[config.Name] = config - - real_path = ManagerUtils.get_bottle_path(config) - for p in [ - os.path.join(real_path, "cache", "dxvk_state"), - os.path.join(real_path, "cache", "gl_shader"), - os.path.join(real_path, "cache", "mesa_shader"), - os.path.join(real_path, "cache", "vkd3d_shader"), - ]: - if not os.path.exists(p): - os.makedirs(p) - - for c in os.listdir(real_path): - c = str(c) - if c.endswith(".dxvk-cache"): - # NOTE: the following code tries to create the caching directories - # if one or more already exist, it will fail silently as there - # is no need to create them again. - try: - shutil.move( - os.path.join(real_path, c), - os.path.join(real_path, "cache", "dxvk_state"), - ) - except shutil.Error: - pass - elif "vkd3d-proton.cache" in c: - try: - shutil.move( - os.path.join(real_path, c), - os.path.join(real_path, "cache", "vkd3d_shader"), - ) - except shutil.Error: - pass - elif c == "GLCache": - try: - shutil.move( - os.path.join(real_path, c), - os.path.join(real_path, "cache", "gl_shader"), - ) - except shutil.Error: - pass - - if config.Parameters.dxvk_nvapi: - NVAPIComponent.check_bottle_nvngx(real_path, config) - - for b in bottles: - """ - For each bottle add the path name to the `local_bottles` variable - and append the config. - """ - process_bottle(b) - - if len(self.local_bottles) > 0 and not silent: - logging.info( - "Bottles found:\n - {}".format("\n - ".join(self.local_bottles)) - ) - # Update parameters in bottle config def update_config( self, @@ -839,7 +685,6 @@ def create_bottle_from_config(self, config: BottleConfig) -> bool: self.install_dll_component(config, "vkd3d") logging.info(f"New bottle from config created: {config.Path}") - self.update_bottles(silent=True) return True def create_bottle( @@ -1153,8 +998,6 @@ def delete_bottle(self, config: BottleConfig) -> bool: path = ManagerUtils.get_bottle_path(config) subprocess.run(["rm", "-rf", path], stdout=subprocess.DEVNULL) - self.update_bottles(silent=True) - logging.info(f"Deleted the bottle in: {path}") return True diff --git a/bottles/frontend/main.py b/bottles/frontend/main.py index 80ed25c2cd9..c56df8f59dc 100644 --- a/bottles/frontend/main.py +++ b/bottles/frontend/main.py @@ -248,16 +248,6 @@ def __help(action=None, param=None): ) webbrowser.open_new_tab("https://docs.usebottles.com") - def __refresh(self, action=None, param=None): - """ - This function refresh the user bottle list. - It is used by the [Ctrl+R] shortcut. - """ - logging.info( - _("[Refresh] request received."), - ) - self.win.manager.update_bottles() - def __show_preferences(self, *args): preferences_window = PreferencesWindow(self.win) preferences_window.present() From 759fba87fd96fc7c342df92b007de13969729fc6 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Mon, 10 Feb 2025 23:05:08 -0500 Subject: [PATCH 143/146] Rework config --- bottles/backend/bottle.py | 22 ++++ bottles/backend/meson.build | 1 + bottles/backend/typing.py | 30 +++++ bottles/frontend/details_preferences_page.py | 1 - bottles/frontend/new-bottle-dialog.blp | 6 +- bottles/frontend/new_bottle_dialog.py | 71 +++++++--- bottles/frontend/window.py | 129 +++++-------------- 7 files changed, 141 insertions(+), 119 deletions(-) create mode 100644 bottles/backend/typing.py diff --git a/bottles/backend/bottle.py b/bottles/backend/bottle.py index 7aa8771cd73..3b004370ed3 100644 --- a/bottles/backend/bottle.py +++ b/bottles/backend/bottle.py @@ -16,10 +16,32 @@ import os import yaml +from dataclasses import dataclass +from typing import Literal +from bottles.backend.typing import WindowsAPI, VersionedComponent, Environment from bottles.backend.models.config import BottleConfig + + +# BottleConfig(Name='d', Arch='win64', Windows='win10', Runner='sys-wine-10.0', WorkingDir='', DXVK='', NVAPI='', VKD3D='', LatencyFleX='', Path='d', Custom_Path=False, Environment='Application', Creation_Date='', Update_Date='', Versioning=False, Versioning_Exclusion_Patterns=[], State=0, Parameters=BottleParams(dxvk=False, dxvk_nvapi=False, vkd3d=False, latencyflex=False, mangohud=False, mangohud_display_on_game_start=True, obsvkc=False, vkbasalt=False, gamemode=False, gamescope=False, gamescope_game_width=0, gamescope_game_height=0, gamescope_window_width=0, gamescope_window_height=0, gamescope_fps=0, gamescope_fps_no_focus=0, gamescope_scaling=False, gamescope_borderless=False, gamescope_fullscreen=True, sync='wine', fsr=False, fsr_sharpening_strength=2, fsr_quality_mode='none', custom_dpi=96, renderer='gl', discrete_gpu=False, virtual_desktop=False, virtual_desktop_res='1280x720', pulseaudio_latency=False, fullscreen_capture=False, take_focus=False, mouse_warp=True, decorated=True, fixme_logs=False, use_runtime=False, use_eac_runtime=True, use_be_runtime=True, use_steam_runtime=False, sandbox=False, versioning_compression=False, versioning_automatic=False, versioning_exclusion_patterns=False, vmtouch=False, vmtouch_cache_cwd=False), Sandbox=BottleSandboxParams(share_net=False, share_sound=False), Environment_Variables={}, Installed_Dependencies=[], DLL_Overrides={}, External_Programs={}, Uninstallers={}, session_arguments='', run_in_terminal=False, Language='sys', CompatData='', data={}, RunnerPath='') +@dataclass +class BottleClass: + name: str + runner: str + environment: Environment + mangohud: bool = False + vkbasalt: bool = False + gamemode: bool = False + gamescope: bool = False + fidelityfx_super_resolution: bool = False + dxvk: VersionedComponent = False + nvapi: VersionedComponent = False + vkd3d: VersionedComponent = False + latencyflex: VersionedComponent = False + architecture: WindowsAPI = WindowsAPI.WIN64 + class Bottle: """Class representing a bottle.""" diff --git a/bottles/backend/meson.build b/bottles/backend/meson.build index b65b506524b..284bb66dce4 100644 --- a/bottles/backend/meson.build +++ b/bottles/backend/meson.build @@ -24,6 +24,7 @@ bottles_sources = [ 'downloader.py', 'cabextract.py', 'state.py', + 'typing.py', params_file ] diff --git a/bottles/backend/typing.py b/bottles/backend/typing.py new file mode 100644 index 00000000000..f24a734b1aa --- /dev/null +++ b/bottles/backend/typing.py @@ -0,0 +1,30 @@ +# typing.py +# +# Copyright 2025 The Bottles Contributors +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, in version 3 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +from typing import Literal +from enum import Enum + +type VersionedComponent = str | Literal[False] + +class WindowsAPI(Enum): + WIN64 = "Win64" + WIN32 = "Win32" + WIN16 = "Win16" + +class Environment(Enum): + APPLICATION = "Application" + GAMING = "Gaming" + CUSTOM = "Custom" diff --git a/bottles/frontend/details_preferences_page.py b/bottles/frontend/details_preferences_page.py index b85fae43f76..5f0ad85c0f8 100644 --- a/bottles/frontend/details_preferences_page.py +++ b/bottles/frontend/details_preferences_page.py @@ -125,7 +125,6 @@ def __init__(self, details, config, **kwargs): # common variables and references self.window = details.window - self.manager = details.window.manager self.config = config self.details = details diff --git a/bottles/frontend/new-bottle-dialog.blp b/bottles/frontend/new-bottle-dialog.blp index d13cc8e8949..d15cb858842 100644 --- a/bottles/frontend/new-bottle-dialog.blp +++ b/bottles/frontend/new-bottle-dialog.blp @@ -69,7 +69,7 @@ template $NewBottleDialog: Adw.Dialog { $CheckRow application { title: _("_Application"); - environment: "application"; + environment: "Application"; subtitle: _("Optimized for productivity software"); icon-name: "applications-engineering-symbolic"; use-underline: true; @@ -78,7 +78,7 @@ template $NewBottleDialog: Adw.Dialog { $CheckRow { title: _("_Gaming"); - environment: "gaming"; + environment: "Gaming"; subtitle: _("Optimized for games, game engines, and 3D apps"); icon-name: "input-gaming-symbolic"; use-underline: true; @@ -87,7 +87,7 @@ template $NewBottleDialog: Adw.Dialog { $CheckRow custom { title: _("C_ustom"); - environment: "custom"; + environment: "Custom"; subtitle: _("A clean state intended for specific use cases"); icon-name: "applications-science-symbolic"; use-underline: true; diff --git a/bottles/frontend/new_bottle_dialog.py b/bottles/frontend/new_bottle_dialog.py index 7cb47c9dbfb..47f1e0df5fb 100644 --- a/bottles/frontend/new_bottle_dialog.py +++ b/bottles/frontend/new_bottle_dialog.py @@ -15,6 +15,9 @@ # along with this program. If not, see . # +import os +import subprocess + from gettext import gettext as _ from typing import Any from gi.repository import Gtk, Adw, Pango, Gio, Xdp, GObject, GLib @@ -84,13 +87,25 @@ def __init__(self, **kwargs: Any) -> None: return self.app = self.window.get_application() - self.manager = self.window.manager self.new_bottle_config = BottleConfig() + self.available_runners = [] + self.available_dxvk_versions = [] self.env_recipe_path = None self.custom_path = "" - self.runner = None self.default_string = _("(Default)") + try: + wine_version = subprocess.check_output(["wine", "--version"], text=True) + wine_version = "sys-" + wine_version.split("\n")[0].split(" ")[0] + self.available_runners.append(wine_version) + except FileNotFoundError: + pass + + self.available_dxvk_versions = self.__get_available_versions_from_component("dxvk") + self.available_nvapi_versions = self.__get_available_versions_from_component("nvapi") + self.available_vkd3d_versions = self.__get_available_versions_from_component("vkd3d") + self.available_runners = self.available_runners + self.__get_available_versions_from_component("runners") + self.arch = {"win64": "64-bit", "win32": "32-bit"} # connect signals @@ -112,16 +127,26 @@ def __init__(self, **kwargs: Any) -> None: # Populate widgets self.label_choose_env.set_label(self.default_string) self.label_choose_path.set_label(self.default_string) - self.str_list_runner.splice(0, 0, self.manager.runners_available) + self.str_list_runner.splice(0, 0, self.available_runners) self.str_list_arch.splice(0, 0, list(self.arch.values())) self.selected_environment = ( self.environment_list_box.get_first_child().environment ) + def __get_available_versions_from_component(self, component: str) -> list[str]: + component_dir = os.path.join(GLib.get_user_data_dir(), "bottles", component) + return os.listdir(component_dir) + + def __get_path(self) -> str: + if self.custom_path: + return self.custom_path + else: + return os.path.join(GLib.get_user_data_dir(), "bottles", self.entry_name.get_text()) + def __check_validity(self, *_args: Any) -> tuple[bool, bool]: is_empty = self.entry_name.get_text() == "" - is_duplicate = self.entry_name.get_text() in self.manager.local_bottles + is_duplicate = self.entry_name.get_text() in self.app.local_bottles return (is_empty, is_duplicate) def __check_entry_name(self, *_args: Any) -> None: @@ -202,24 +227,34 @@ def set_path(dialog, result): def create_bottle(self, *_args: Any) -> None: """Starts creating the bottle.""" # set widgets states - self.set_can_close(False) + # self.set_can_close(False) TODO: UNCOMMENT self.stack_create.set_visible_child_name("page_creating") - self.runner = self.manager.runners_available[self.combo_runner.get_selected()] - - RunAsync( - task_func=self.manager.create_bottle, - callback=self.finish, - name=self.entry_name.get_text(), - path=self.custom_path, - environment=self.selected_environment, - runner=self.runner, - arch=list(self.arch)[self.combo_arch.get_selected()], - dxvk=self.manager.dxvk_available[0], - fn_logger=self.update_output, - custom_environment=self.env_recipe_path, + + config = BottleConfig( + Name=self.entry_name.get_text(), + Arch=list(self.arch)[self.combo_arch.get_selected()], + Runner=self.available_runners[self.combo_runner.get_selected()], + Custom_Path=bool(self.custom_path), + Path=os.path.join(self.custom_path, self.entry_name.get_text()), + Environment=self.selected_environment, ) + print(config) + + # RunAsync( + # task_func=self.manager.create_bottle, + # callback=self.finish, + # name=self.entry_name.get_text(), + # path=self.custom_path, + # environment=self.selected_environment, + # runner=runner, + # arch=list(self.arch)[self.combo_arch.get_selected()], + # dxvk=self.available_dxvk_versions[0], + # fn_logger=self.update_output, + # custom_environment=self.env_recipe_path, + # ) + @GtkUtils.run_in_main_loop def update_output(self, text: str) -> None: """ diff --git a/bottles/frontend/window.py b/bottles/frontend/window.py index f0a434b4453..d898262e89d 100644 --- a/bottles/frontend/window.py +++ b/bottles/frontend/window.py @@ -25,12 +25,9 @@ from bottles.backend.globals import Paths from bottles.backend.health import HealthChecker import logging -from bottles.backend.managers.manager import Manager from bottles.backend.models.config import BottleConfig from bottles.backend.models.result import Result -from bottles.backend.state import SignalManager, Signals, Notification from bottles.backend.utils.threading import RunAsync -from bottles.frontend.operation import TaskSyncer from bottles.frontend.params import APP_ID, BASE_ID, PROFILE from bottles.frontend.gtk import GtkUtils from bottles.frontend.bottle_details_view import BottleDetailsView @@ -126,115 +123,53 @@ def response(dialog, response, *args): self.btn_add.connect("clicked", self.show_add_view) self.stack_main.connect("notify::visible-child", self.__on_page_changed) - # backend signal handlers - self.task_syncer = TaskSyncer(self) - SignalManager.connect(Signals.TaskAdded, self.task_syncer.task_added_handler) - SignalManager.connect( - Signals.TaskRemoved, self.task_syncer.task_removed_handler - ) - SignalManager.connect( - Signals.TaskUpdated, self.task_syncer.task_updated_handler - ) - SignalManager.connect( - Signals.NetworkStatusChanged, self.network_changed_handler + # Pages + self.page_details = BottleDetailsView(self) + self.page_list = BottlesListView() + + self.main_leaf.append(self.page_details) + + self.main_leaf.get_page(self.page_details).set_navigatable(False) + + self.stack_main.add_titled( + child=self.page_list, name="page_list", title=_("Bottles") + ).set_icon_name(f"{APP_ID}-symbolic") + + self.page_list.search_bar.set_key_capture_widget(self) + self.btn_search.bind_property( + "active", + self.page_list.search_bar, + "search-mode-enabled", + GObject.BindingFlags.BIDIRECTIONAL, ) - SignalManager.connect(Signals.GNotification, self.g_notification_handler) - SignalManager.connect(Signals.GShowUri, self.g_show_uri_handler) - self.__on_start() - logging.info( - "Bottles Started!", + if ( + self.stack_main.get_child_by_name(self.settings.get_string("startup-view")) + is None + ): + self.stack_main.set_visible_child_name("page_list") + + self.settings.bind( + "startup-view", + self.stack_main, + "visible-child-name", + Gio.SettingsBindFlags.DEFAULT, ) + self.lock_ui(False) + self.headerbar.get_style_context().remove_class("flat") + @Gtk.Template.Callback() def on_close_request(self, *args): self.settings.set_int("window-width", self.get_width()) self.settings.set_int("window-height", self.get_height()) - # region Backend signal handlers - def network_changed_handler(self, res: Result): - GLib.idle_add(self.btn_noconnection.set_visible, not res.status) - - def g_notification_handler(self, res: Result): - """handle backend notification request""" - notify: Notification = res.data - self.send_notification(title=notify.title, text=notify.text, image=notify.image) - - def g_show_uri_handler(self, res: Result): - """handle backend show_uri request""" - uri: str = res.data - Gtk.show_uri(self, uri, Gdk.CURRENT_TIME) - # endregion def title(self, title, subtitle: str = ""): self.view_switcher_title.set_title(title) self.view_switcher_title.set_subtitle(subtitle) - def __on_start(self): - """ - This method is called before the window is shown. This check if there - is at least one local runner installed. If not, the user will be - prompted with the onboard dialog. - """ - - @GtkUtils.run_in_main_loop - def set_manager(result: Manager, error=None): - self.manager = result - - tmp_runners = [ - x for x in self.manager.runners_available if not x.startswith("sys-") - ] - if len(tmp_runners) == 0: - self.show_onboard_view() - - # Pages - self.page_details = BottleDetailsView(self) - self.page_list = BottlesListView() - - self.main_leaf.append(self.page_details) - - self.main_leaf.get_page(self.page_details).set_navigatable(False) - - self.stack_main.add_titled( - child=self.page_list, name="page_list", title=_("Bottles") - ).set_icon_name(f"{APP_ID}-symbolic") - - self.page_list.search_bar.set_key_capture_widget(self) - self.btn_search.bind_property( - "active", - self.page_list.search_bar, - "search-mode-enabled", - GObject.BindingFlags.BIDIRECTIONAL, - ) - - if ( - self.stack_main.get_child_by_name( - self.settings.get_string("startup-view") - ) - is None - ): - self.stack_main.set_visible_child_name("page_list") - - self.settings.bind( - "startup-view", - self.stack_main, - "visible-child-name", - Gio.SettingsBindFlags.DEFAULT, - ) - - self.lock_ui(False) - self.headerbar.get_style_context().remove_class("flat") - - def get_manager(): - # do not redo connection if aborted connection - mng = Manager(g_settings=self.settings) - return mng - - RunAsync(get_manager, callback=set_manager) - - self.check_crash_log() - def send_notification(self, title, text, image="", ignore_user=False): """ This method is used to send a notification to the user using From 923ac335f76a4479cbad4d6de8f228506371e597 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Mon, 10 Feb 2025 23:05:55 -0500 Subject: [PATCH 144/146] pre-commit --- bottles/backend/bottle.py | 4 +--- bottles/backend/typing.py | 2 ++ bottles/frontend/new_bottle_dialog.py | 22 ++++++++++++++++------ 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/bottles/backend/bottle.py b/bottles/backend/bottle.py index 3b004370ed3..7170f3bddeb 100644 --- a/bottles/backend/bottle.py +++ b/bottles/backend/bottle.py @@ -17,14 +17,11 @@ import os import yaml from dataclasses import dataclass -from typing import Literal from bottles.backend.typing import WindowsAPI, VersionedComponent, Environment from bottles.backend.models.config import BottleConfig - - # BottleConfig(Name='d', Arch='win64', Windows='win10', Runner='sys-wine-10.0', WorkingDir='', DXVK='', NVAPI='', VKD3D='', LatencyFleX='', Path='d', Custom_Path=False, Environment='Application', Creation_Date='', Update_Date='', Versioning=False, Versioning_Exclusion_Patterns=[], State=0, Parameters=BottleParams(dxvk=False, dxvk_nvapi=False, vkd3d=False, latencyflex=False, mangohud=False, mangohud_display_on_game_start=True, obsvkc=False, vkbasalt=False, gamemode=False, gamescope=False, gamescope_game_width=0, gamescope_game_height=0, gamescope_window_width=0, gamescope_window_height=0, gamescope_fps=0, gamescope_fps_no_focus=0, gamescope_scaling=False, gamescope_borderless=False, gamescope_fullscreen=True, sync='wine', fsr=False, fsr_sharpening_strength=2, fsr_quality_mode='none', custom_dpi=96, renderer='gl', discrete_gpu=False, virtual_desktop=False, virtual_desktop_res='1280x720', pulseaudio_latency=False, fullscreen_capture=False, take_focus=False, mouse_warp=True, decorated=True, fixme_logs=False, use_runtime=False, use_eac_runtime=True, use_be_runtime=True, use_steam_runtime=False, sandbox=False, versioning_compression=False, versioning_automatic=False, versioning_exclusion_patterns=False, vmtouch=False, vmtouch_cache_cwd=False), Sandbox=BottleSandboxParams(share_net=False, share_sound=False), Environment_Variables={}, Installed_Dependencies=[], DLL_Overrides={}, External_Programs={}, Uninstallers={}, session_arguments='', run_in_terminal=False, Language='sys', CompatData='', data={}, RunnerPath='') @dataclass class BottleClass: @@ -42,6 +39,7 @@ class BottleClass: latencyflex: VersionedComponent = False architecture: WindowsAPI = WindowsAPI.WIN64 + class Bottle: """Class representing a bottle.""" diff --git a/bottles/backend/typing.py b/bottles/backend/typing.py index f24a734b1aa..676100e5363 100644 --- a/bottles/backend/typing.py +++ b/bottles/backend/typing.py @@ -19,11 +19,13 @@ type VersionedComponent = str | Literal[False] + class WindowsAPI(Enum): WIN64 = "Win64" WIN32 = "Win32" WIN16 = "Win16" + class Environment(Enum): APPLICATION = "Application" GAMING = "Gaming" diff --git a/bottles/frontend/new_bottle_dialog.py b/bottles/frontend/new_bottle_dialog.py index 47f1e0df5fb..34e46cdd276 100644 --- a/bottles/frontend/new_bottle_dialog.py +++ b/bottles/frontend/new_bottle_dialog.py @@ -101,10 +101,19 @@ def __init__(self, **kwargs: Any) -> None: except FileNotFoundError: pass - self.available_dxvk_versions = self.__get_available_versions_from_component("dxvk") - self.available_nvapi_versions = self.__get_available_versions_from_component("nvapi") - self.available_vkd3d_versions = self.__get_available_versions_from_component("vkd3d") - self.available_runners = self.available_runners + self.__get_available_versions_from_component("runners") + self.available_dxvk_versions = self.__get_available_versions_from_component( + "dxvk" + ) + self.available_nvapi_versions = self.__get_available_versions_from_component( + "nvapi" + ) + self.available_vkd3d_versions = self.__get_available_versions_from_component( + "vkd3d" + ) + self.available_runners = ( + self.available_runners + + self.__get_available_versions_from_component("runners") + ) self.arch = {"win64": "64-bit", "win32": "32-bit"} @@ -142,7 +151,9 @@ def __get_path(self) -> str: if self.custom_path: return self.custom_path else: - return os.path.join(GLib.get_user_data_dir(), "bottles", self.entry_name.get_text()) + return os.path.join( + GLib.get_user_data_dir(), "bottles", self.entry_name.get_text() + ) def __check_validity(self, *_args: Any) -> tuple[bool, bool]: is_empty = self.entry_name.get_text() == "" @@ -230,7 +241,6 @@ def create_bottle(self, *_args: Any) -> None: # self.set_can_close(False) TODO: UNCOMMENT self.stack_create.set_visible_child_name("page_creating") - config = BottleConfig( Name=self.entry_name.get_text(), Arch=list(self.arch)[self.combo_arch.get_selected()], From e1ceceedcab6c88043a577fca231df61c65909e9 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Sun, 9 Mar 2025 19:18:12 -0400 Subject: [PATCH 145/146] meh --- bottles/frontend/bottle_details_page.py | 6 ++++-- bottles/frontend/bottle_details_view.py | 2 +- bottles/frontend/details_preferences_page.py | 18 ++++++++---------- bottles/frontend/main.py | 3 ++- 4 files changed, 15 insertions(+), 14 deletions(-) diff --git a/bottles/frontend/bottle_details_page.py b/bottles/frontend/bottle_details_page.py index 2a6fdeec88f..5a79f966e34 100644 --- a/bottles/frontend/bottle_details_page.py +++ b/bottles/frontend/bottle_details_page.py @@ -15,6 +15,7 @@ # along with this program. If not, see . # +import os import uuid from datetime import datetime from gettext import gettext as _ @@ -98,7 +99,6 @@ def __init__(self, details, config, **kwargs): # common variables and references self.window = details.window - self.manager = details.window.manager self.stack_bottle = details.stack_bottle self.leaflet = details.leaflet self.details = details @@ -209,8 +209,10 @@ def set_config(self, config: BottleConfig): self.grid_versioning.set_visible(self.config.Versioning) self.label_state.set_text(str(self.config.State)) + app = self.window.get_application() + if ( - config.Runner not in self.manager.runners_available + config.Runner not in os.listdir(os.path.join(app.bottles_data_dir, "runners")) and not self.config.Environment == "Steam" ): self.__alert_missing_runner() diff --git a/bottles/frontend/bottle_details_view.py b/bottles/frontend/bottle_details_view.py index 8177b8d828c..be0cb007a54 100644 --- a/bottles/frontend/bottle_details_view.py +++ b/bottles/frontend/bottle_details_view.py @@ -71,7 +71,7 @@ def __init__(self, window, config: BottleConfig | None = None, **kwargs): self.view_bottle = BottleDetailsPage(self, config) self.view_dependencies = DetailsDependenciesView(self, config) - self.view_preferences = DetailsPreferencesPage(self, config) + self.view_preferences = DetailsPreferencesPage() self.view_taskmanager = DetailsTaskManagerView(self, config) self.btn_back.connect("clicked", self.go_back) diff --git a/bottles/frontend/details_preferences_page.py b/bottles/frontend/details_preferences_page.py index 5f0ad85c0f8..106404c3aab 100644 --- a/bottles/frontend/details_preferences_page.py +++ b/bottles/frontend/details_preferences_page.py @@ -120,13 +120,10 @@ class DetailsPreferencesPage(Adw.PreferencesPage): # endregion - def __init__(self, details, config, **kwargs): + def __init__(self, **kwargs): super().__init__(**kwargs) - # common variables and references - self.window = details.window - self.config = config - self.details = details + self.window = GtkUtils.get_parent_window() if not gamemode_available or not Xdp.Portal.running_under_sandbox(): return @@ -336,19 +333,20 @@ def update_combo_components(self): self.str_list_dxvk.append("Disabled") self.str_list_vkd3d.append("Disabled") self.str_list_latencyflex.append("Disabled") - for index, dxvk in enumerate(self.manager.dxvk_available): + app = self.window.get_application() + for index, dxvk in enumerate(os.path.join(app.bottles_data_dir, "dxvk")): self.str_list_dxvk.append(dxvk) - for index, vkd3d in enumerate(self.manager.vkd3d_available): + for index, vkd3d in enumerate(os.path.join(app.bottles_data_dir, "vkd3d")): self.str_list_vkd3d.append(vkd3d) - for index, runner in enumerate(self.manager.runners_available): + for index, runner in enumerate(os.path.join(app.bottles_data_dir, "runners")): self.str_list_runner.append(runner) - for index, nvapi in enumerate(self.manager.nvapi_available): + for index, nvapi in enumerate(os.path.join(app.bottles_data_dir, "nvapi")): self.str_list_nvapi.append(nvapi) - for index, latencyflex in enumerate(self.manager.latencyflex_available): + for index, latencyflex in enumerate(os.path.join(app.bottles_data_dir, "latencyflex")): self.str_list_latencyflex.append(latencyflex) for lang in ManagerUtils.get_languages(): diff --git a/bottles/frontend/main.py b/bottles/frontend/main.py index c56df8f59dc..e4e059b42c5 100644 --- a/bottles/frontend/main.py +++ b/bottles/frontend/main.py @@ -49,7 +49,8 @@ class Bottles(Adw.Application): arg_bottle = None dark_provider = None local_bottles: dict[str, BottleConfig] = {} - bottles_config_dir = os.path.join(GLib.get_user_data_dir(), "bottles", "bottles") + bottles_data_dir = os.path.join(GLib.get_user_data_dir(), "bottles") + bottles_config_dir = os.path.join(bottles_data_dir, "bottles") def __init__(self): super().__init__( From 4089e62a2cc95d3b4d0c3ab9c71a9da9ee5ab3d3 Mon Sep 17 00:00:00 2001 From: Hari Rana Date: Sun, 13 Apr 2025 08:55:37 -0400 Subject: [PATCH 146/146] pre-commit --- bottles/frontend/bottle_details_page.py | 3 ++- bottles/frontend/details_preferences_page.py | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/bottles/frontend/bottle_details_page.py b/bottles/frontend/bottle_details_page.py index 5a79f966e34..84ef99b1d95 100644 --- a/bottles/frontend/bottle_details_page.py +++ b/bottles/frontend/bottle_details_page.py @@ -212,7 +212,8 @@ def set_config(self, config: BottleConfig): app = self.window.get_application() if ( - config.Runner not in os.listdir(os.path.join(app.bottles_data_dir, "runners")) + config.Runner + not in os.listdir(os.path.join(app.bottles_data_dir, "runners")) and not self.config.Environment == "Steam" ): self.__alert_missing_runner() diff --git a/bottles/frontend/details_preferences_page.py b/bottles/frontend/details_preferences_page.py index 106404c3aab..3da939d13a2 100644 --- a/bottles/frontend/details_preferences_page.py +++ b/bottles/frontend/details_preferences_page.py @@ -346,7 +346,9 @@ def update_combo_components(self): for index, nvapi in enumerate(os.path.join(app.bottles_data_dir, "nvapi")): self.str_list_nvapi.append(nvapi) - for index, latencyflex in enumerate(os.path.join(app.bottles_data_dir, "latencyflex")): + for index, latencyflex in enumerate( + os.path.join(app.bottles_data_dir, "latencyflex") + ): self.str_list_latencyflex.append(latencyflex) for lang in ManagerUtils.get_languages():