├── .github
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── feature_request.md
├── pull_request_template.md
└── workflows
│ └── main.yml
├── .gitignore
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE.md
├── README.md
├── SECURITY.md
├── com.vysp3r.ProtonPlus.local.yml
├── com.vysp3r.ProtonPlus.yml
├── data
├── com.vysp3r.ProtonPlus.desktop.in
├── com.vysp3r.ProtonPlus.gschema.xml
├── com.vysp3r.ProtonPlus.metainfo.xml.in
├── css
│ ├── css.gresource.xml
│ ├── meson.build
│ └── style.css
├── icons
│ ├── circle-check.svg
│ ├── circle-chevron-up.svg
│ ├── dots.svg
│ ├── download.svg
│ ├── icons.gresource.xml
│ ├── info-circle.svg
│ ├── journal-text.svg
│ ├── meson.build
│ ├── trash.svg
│ ├── world-www.svg
│ └── x.svg
├── images
│ ├── images.gresource.xml
│ ├── launchers
│ │ ├── bottles.png
│ │ ├── hgl.png
│ │ ├── lutris.png
│ │ └── steam.png
│ └── meson.build
├── logo
│ ├── ProtonPlus.xcf
│ ├── com.vysp3r.ProtonPlus.svg
│ └── icons
│ │ └── hicolor
│ │ ├── 128x128
│ │ └── apps
│ │ │ └── com.vysp3r.ProtonPlus.png
│ │ ├── 16x16
│ │ └── apps
│ │ │ └── com.vysp3r.ProtonPlus.png
│ │ ├── 256x256
│ │ └── apps
│ │ │ └── com.vysp3r.ProtonPlus.png
│ │ ├── 32x32
│ │ └── apps
│ │ │ └── com.vysp3r.ProtonPlus.png
│ │ ├── 48x48
│ │ └── apps
│ │ │ └── com.vysp3r.ProtonPlus.png
│ │ ├── 512x512
│ │ └── apps
│ │ │ └── com.vysp3r.ProtonPlus.png
│ │ └── 64x64
│ │ └── apps
│ │ └── com.vysp3r.ProtonPlus.png
├── meson.build
├── previews
│ └── Preview-1.png
└── ui
│ ├── gtk
│ └── help-overlay.ui
│ ├── meson.build
│ └── ui.gresource.xml
├── meson.build
├── po
├── LINGUAS
├── POTFILES
├── be.po
├── com.vysp3r.ProtonPlus.pot
├── cs.po
├── de.po
├── es.po
├── fi.po
├── fr.po
├── id.po
├── it.po
├── meson.build
├── pl.po
├── pt.po
├── ru.po
├── sv.po
├── zh.po
└── zh_TW.po
├── scripts
├── build-flathub.sh
├── build-local.sh
├── build-native.sh
├── flathub-linter.sh
├── generate-icons.sh
├── rebuild-translations.sh
└── set-version.py
└── src
├── config.vapi
├── main.vala
├── meson.build
├── models
├── group.vala
├── launcher.vala
├── launchers
│ ├── bottles.vala
│ ├── hgl.vala
│ ├── lutris.vala
│ └── steam.vala
├── parameters.vala
├── release.vala
├── releases
│ ├── basic.vala
│ ├── github-action.vala
│ ├── steamtinkerlaunch.vala
│ └── upgrade.vala
├── runner.vala
└── runners
│ ├── basic.vala
│ ├── boxtron.vala
│ ├── dxvk-async-sarek.vala
│ ├── dxvk-doitsujin.vala
│ ├── dxvk-gpl-async-ph42on.vala
│ ├── dxvk-sarek.vala
│ ├── github-action.vala
│ ├── github.vala
│ ├── gitlab.vala
│ ├── kron4ek-wine-builds-staging-tkg.vala
│ ├── kron4ek-wine-builds-staging.vala
│ ├── kron4ek-wine-builds-vanilla.vala
│ ├── luxtorpeda.vala
│ ├── northstar-proton.vala
│ ├── other.vala
│ ├── proton-cachyos.vala
│ ├── proton-em.vala
│ ├── proton-ge-rstp.vala
│ ├── proton-ge.vala
│ ├── proton-sarek-async.vala
│ ├── proton-sarek.vala
│ ├── proton-tkg.vala
│ ├── roberta.vala
│ ├── steamtinkerlaunch.vala
│ ├── vkd3d-lutris.vala
│ └── vkd3d-proton.vala
├── utils
├── filesystem.vala
├── parser.vala
├── system.vala
└── web.vala
└── widgets
├── application.vala
├── busy-dialog.vala
├── busy-dialogs
├── install-dialog.vala
├── remove-dialog.vala
└── upgrade-dialog.vala
├── description-dialog.vala
├── info-box.vala
├── launcher-box.vala
├── load-more-row.vala
├── release-row.vala
├── release-rows
├── basic.vala
└── steamtinkerlaunch.vala
├── runner-group.vala
├── runner-row.vala
├── sidebar-row.vala
├── sidebar.vala
├── status-box.vala
└── window.vala
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: "[BUG]"
5 | labels: bug
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | A clear and concise description of what the bug is.
12 |
13 | **To Reproduce**
14 | Steps to reproduce the behavior:
15 | 1. Go to '...'
16 | 2. Click on '....'
17 | 3. Scroll down to '....'
18 | 4. See error
19 |
20 | **Expected behavior**
21 | A clear and concise description of what you expected to happen.
22 |
23 | **Screenshots**
24 | If applicable, add screenshots to help explain your problem.
25 |
26 | **Desktop (please complete the following information):**
27 | - OS: [e.g. Fedora 36]
28 | - DE: [e.g. GNOME 42]
29 | - Type: [source or Flatpak]
30 |
31 | **Additional context**
32 | Add any other context about the problem here.
33 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: "[FEATURE]"
5 | labels: enhancement
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12 |
13 | **Describe the solution you'd like**
14 | A clear and concise description of what you want to happen.
15 |
16 | **Describe alternatives you've considered**
17 | A clear and concise description of any alternative solutions or features you've considered.
18 |
19 | **Additional context**
20 | Add any other context or screenshots about the feature request here.
21 |
--------------------------------------------------------------------------------
/.github/pull_request_template.md:
--------------------------------------------------------------------------------
1 | *Thank you for contributing to ProtonPlus! So that your Pull Request can be handled effectively, please populate the following fields (delete sections that are not applicable)*
2 |
3 | ### Category
4 | > One of: Bugfix / Feature / Code style update / Refactoring Only / Build related changes / Documentation / Other (Please specify!)
5 |
6 | ### Overview
7 | > Briefly outline your new changes...
8 |
9 | ### Issue Number _(if applicable)_
10 | > Related issue: #00
11 |
12 | ### New Vars _(if applicable)_
13 | > If you've added any new build scripts, environmental variables, config file options, dependency please outline here.
14 |
15 | ### Screenshot _(if applicable)_
16 | > If you've introduced any significant UI changes, please include a screenshot.
17 |
18 |
--------------------------------------------------------------------------------
/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | name: Build & Check
2 |
3 | on:
4 | pull_request:
5 | branches:
6 | - main
7 |
8 | jobs:
9 | build:
10 | name: Build
11 | runs-on: ubuntu-latest
12 | steps:
13 | - name: Install dependencies
14 | run: |
15 | sudo apt update
16 | sudo apt install gettext valac meson libadwaita-1-dev libarchive-dev libgee-0.8-dev libgtk-4-dev libjson-glib-dev libsoup-3.0-dev desktop-file-utils appstream-util
17 | - name: Checkout pull request
18 | uses: actions/checkout@v4.2.2
19 | with:
20 | ref: ${{ github.event.pull_request.head.sha }}
21 | - name: Build
22 | run: |
23 | mkdir build
24 | meson --prefix=/usr build
25 | meson compile -C build
26 | - name: Check
27 | run: 'meson test -C build --print-errorlogs || :'
28 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Temporary build files.
2 | _build/
3 | .flatpak-builder/
4 | .flatpak/
5 | build-dir/
6 | build-flatpak/
7 | build-native/
8 | build/
9 |
10 | # Miscellaneous.
11 | .vscode/
12 | gdb.sh
13 | com.vysp3r.ProtonPlus.flatpak
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | We as members, contributors, and leaders pledge to make participation in our
6 | community a harassment-free experience for everyone, regardless of age, body
7 | size, visible or invisible disability, ethnicity, sex characteristics, gender
8 | identity and expression, level of experience, education, socio-economic status,
9 | nationality, personal appearance, race, religion, or sexual identity
10 | and orientation.
11 |
12 | We pledge to act and interact in ways that contribute to an open, welcoming,
13 | diverse, inclusive, and healthy community.
14 |
15 | ## Our Standards
16 |
17 | Examples of behavior that contributes to a positive environment for our
18 | community include:
19 |
20 | * Demonstrating empathy and kindness toward other people
21 | * Being respectful of differing opinions, viewpoints, and experiences
22 | * Giving and gracefully accepting constructive feedback
23 | * Accepting responsibility and apologizing to those affected by our mistakes,
24 | and learning from the experience
25 | * Focusing on what is best not just for us as individuals, but for the
26 | overall community
27 |
28 | Examples of unacceptable behavior include:
29 |
30 | * The use of sexualized language or imagery, and sexual attention or
31 | advances of any kind
32 | * Trolling, insulting or derogatory comments, and personal or political attacks
33 | * Public or private harassment
34 | * Publishing others' private information, such as a physical or email
35 | address, without their explicit permission
36 | * Other conduct which could reasonably be considered inappropriate in a
37 | professional setting
38 |
39 | ## Enforcement Responsibilities
40 |
41 | Community leaders are responsible for clarifying and enforcing our standards of
42 | acceptable behavior and will take appropriate and fair corrective action in
43 | response to any behavior that they deem inappropriate, threatening, offensive,
44 | or harmful.
45 |
46 | Community leaders have the right and responsibility to remove, edit, or reject
47 | comments, commits, code, wiki edits, issues, and other contributions that are
48 | not aligned to this Code of Conduct, and will communicate reasons for moderation
49 | decisions when appropriate.
50 |
51 | ## Scope
52 |
53 | This Code of Conduct applies within all community spaces, and also applies when
54 | an individual is officially representing the community in public spaces.
55 | Examples of representing our community include using an official e-mail address,
56 | posting via an official social media account, or acting as an appointed
57 | representative at an online or offline event.
58 |
59 | ## Enforcement
60 |
61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
62 | reported to the community leaders responsible for enforcement at
63 | protonplus@vysp3r.com.
64 | All complaints will be reviewed and investigated promptly and fairly.
65 |
66 | All community leaders are obligated to respect the privacy and security of the
67 | reporter of any incident.
68 |
69 | ## Enforcement Guidelines
70 |
71 | Community leaders will follow these Community Impact Guidelines in determining
72 | the consequences for any action they deem in violation of this Code of Conduct:
73 |
74 | ### 1. Correction
75 |
76 | **Community Impact**: Use of inappropriate language or other behavior deemed
77 | unprofessional or unwelcome in the community.
78 |
79 | **Consequence**: A private, written warning from community leaders, providing
80 | clarity around the nature of the violation and an explanation of why the
81 | behavior was inappropriate. A public apology may be requested.
82 |
83 | ### 2. Warning
84 |
85 | **Community Impact**: A violation through a single incident or series
86 | of actions.
87 |
88 | **Consequence**: A warning with consequences for continued behavior. No
89 | interaction with the people involved, including unsolicited interaction with
90 | those enforcing the Code of Conduct, for a specified period of time. This
91 | includes avoiding interactions in community spaces as well as external channels
92 | like social media. Violating these terms may lead to a temporary or
93 | permanent ban.
94 |
95 | ### 3. Temporary Ban
96 |
97 | **Community Impact**: A serious violation of community standards, including
98 | sustained inappropriate behavior.
99 |
100 | **Consequence**: A temporary ban from any sort of interaction or public
101 | communication with the community for a specified period of time. No public or
102 | private interaction with the people involved, including unsolicited interaction
103 | with those enforcing the Code of Conduct, is allowed during this period.
104 | Violating these terms may lead to a permanent ban.
105 |
106 | ### 4. Permanent Ban
107 |
108 | **Community Impact**: Demonstrating a pattern of violation of community
109 | standards, including sustained inappropriate behavior, harassment of an
110 | individual, or aggression toward or disparagement of classes of individuals.
111 |
112 | **Consequence**: A permanent ban from any sort of public interaction within
113 | the community.
114 |
115 | ## Attribution
116 |
117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage],
118 | version 2.0, available at
119 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
120 |
121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct
122 | enforcement ladder](https://github.com/mozilla/diversity).
123 |
124 | [homepage]: https://www.contributor-covenant.org
125 |
126 | For answers to common questions about this code of conduct, see the FAQ at
127 | https://www.contributor-covenant.org/faq. Translations are available at
128 | https://www.contributor-covenant.org/translations.
129 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing to ProtonPlus
2 |
3 | First off, thanks for taking the time to contribute! ❤️
4 |
5 | All types of contributions are encouraged and valued. See the [Table of Contents](#table-of-contents) for different ways to help and details about how this project handles them. Please make sure to read the relevant section before making your contribution. It will make it a lot easier for us maintainers and smooth out the experience for all involved. The community looks forward to your contributions. 🎉
6 |
7 | > And if you like the project, but just don't have time to contribute, that's fine. There are other easy ways to support the project and show your appreciation, which we would also be very happy about:
8 | > - Star the project
9 | > - Tweet about it
10 | > - Refer this project in your project's readme
11 | > - Mention the project at local meetups and tell your friends/colleagues
12 |
13 | ## Table of Contents
14 |
15 | - [I Have a Question](#i-have-a-question)
16 | - [I Want To Contribute](#i-want-to-contribute)
17 | - [Reporting Bugs](#reporting-bugs)
18 | - [Suggesting Enhancements](#suggesting-enhancements)
19 | - [Styleguides](#styleguides)
20 | - [Commit Messages](#commit-messages)
21 |
22 |
23 | ## Code of Conduct
24 |
25 | This project and everyone participating in it is governed by the
26 | [ProtonPlus Code of Conduct](https://github.com/Vysp3r/ProtonPlus/blob/master/CODE_OF_CONDUCT.md).
27 | By participating, you are expected to uphold this code. Please report unacceptable behavior
28 | to [@Vysp3r](https://github.com/Vysp3r).
29 |
30 | ## I Have a Question
31 |
32 | > If you want to ask a question, we assume that you have read the available [Documentation](https://github.com/Vysp3r/ProtonPlus/#readme).
33 |
34 | Before you ask a question, it is best to search for existing [Issues](https://github.com/Vysp3r/ProtonPlus/issues) that might help you. In case you have found a suitable issue and still need clarification, you can write your question in this issue. It is also advisable to search the internet for answers first.
35 |
36 | If you then still feel the need to ask a question and need clarification, we recommend the following:
37 |
38 | - Open an [Issue](https://github.com/Vysp3r/ProtonPlus/issues/new).
39 | - Provide as much context as you can about what you're running into.
40 |
41 | We will then take care of the issue as soon as possible.
42 |
43 | ## I Want To Contribute
44 |
45 | > ### Legal Notice
46 | > When contributing to this project, you must agree that you have authored 100% of the content, that you have the necessary rights to the content and that the content you contribute may be provided under the project license.
47 |
48 | ### Reporting Bugs
49 |
50 | #### Before Submitting a Bug Report
51 |
52 | A good bug report shouldn't leave others needing to chase you up for more information. Therefore, we ask you to investigate carefully, collect information and describe the issue in detail in your report. Please complete the following steps in advance to help us fix any potential bug as fast as possible.
53 |
54 | - Make sure that you are using the latest version.
55 | - Determine if your bug is really a bug and not an error on your side e.g. using incompatible environment components/versions (Make sure that you have read the [documentation](https://github.com/Vysp3r/ProtonPlus/#readme). If you are looking for support, you might want to check [this section](#i-have-a-question)).
56 | - To see if other users have experienced (and potentially already solved) the same issue you are having, check if there is not already a bug report existing for your bug or error in the [bug tracker](https://github.com/Vysp3r/ProtonPlus/issues?q=is%3Aopen+is%3Aissue+label%3A%22%F0%9F%90%9B+Bug%22).
57 | - Also make sure to search the internet (including Stack Overflow) to see if users outside of the GitHub community have discussed the issue.
58 | - Collect information about the bug:
59 | - Stack trace (Traceback)
60 | - OS, Platform and Version (Windows, Linux, macOS, x86, ARM)
61 | - Possibly your input and the output
62 | - Can you reliably reproduce the issue? And can you also reproduce it with older versions?
63 |
64 | #### How Do I Submit a Good Bug Report?
65 |
66 | > You must never report security related issues, vulnerabilities or bugs including sensitive information to the issue tracker, or elsewhere in public. Instead sensitive bugs must be sent by email to vyspr@tuta.io.
67 |
68 | We use GitHub issues to track bugs and errors. If you run into an issue with the project:
69 |
70 | - Open an [Issue](https://github.com/Vysp3r/ProtonPlus/issues/new).
71 | - Explain the behavior you would expect and the actual behavior.
72 | - Please provide as much context as possible and describe the *reproduction steps* that someone else can follow to recreate the issue on their own. This usually includes your code. For good bug reports you should isolate the problem and create a reduced test case.
73 | - Provide the information you collected in the previous section.
74 |
75 |
76 | ### Suggesting Enhancements
77 |
78 | This section guides you through submitting an enhancement suggestion for ProtonPlus, **including completely new features and minor improvements to existing functionality**. Following these guidelines will help maintainers and the community to understand your suggestion and find related suggestions.
79 |
80 | #### Before Submitting an Enhancement
81 |
82 | - Make sure that you are using the latest version.
83 | - Read the [documentation](https://github.com/Vysp3r/ProtonPlus/#readme) carefully and find out if the functionality is already covered, maybe by an individual configuration.
84 | - Perform a [search](https://github.com/Vysp3r/ProtonPlus/issues) to see if the enhancement has already been suggested. If it has, add a comment to the existing issue instead of opening a new one.
85 | - Find out whether your idea fits with the scope and aims of the project. It's up to you to make a strong case to convince the project's developers of the merits of this feature. Keep in mind that we want features that will be useful to the majority of our users and not just a small subset. If you're just targeting a minority of users, consider writing an add-on/plugin library.
86 |
87 | #### How Do I Submit a Good Enhancement Suggestion?
88 |
89 | Enhancement suggestions are tracked as [GitHub issues](https://github.com/Vysp3r/ProtonPlus/issues).
90 |
91 | - Use a **clear and descriptive title** for the issue to identify the suggestion.
92 | - Provide a **step-by-step description of the suggested enhancement** in as many details as possible.
93 | - **Describe the current behavior** and **explain which behavior you expected to see instead** and why. At this point you can also tell which alternatives do not work for you.
94 | - You may want to **include screenshots and animated GIFs** which help you demonstrate the steps or point out the part which the suggestion is related to. You can use [this tool](https://github.com/ShareX/ShareX) to record GIFs on Windows, and [this tool](https://github.com/phw/peek) on linux.
95 | - **Explain why this enhancement would be useful** to most ProtonPlus users. You may also want to point out the other projects that solved it better and which could serve as inspiration.
96 |
97 | ## Styleguides
98 | ### Commit Messages
99 |
100 | ProtonPlus uses [GitMoji](https://gitmoji.dev/).
101 | We would appreciate it if everyone keeps their commit messages withing these rulings.
102 |
103 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ProtonPlus
5 |
6 |
7 |
8 | A modern compatibility tools manager for Linux.
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 | Don't forget to star the repo if you are enjoying the project!
31 |
32 |
33 | [ ](https://flathub.org/apps/details/com.vysp3r.ProtonPlus)
34 |
35 | ## 📦️ Installation methods
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 | > [!WARNING]
44 | > The main installation method is Flathub
45 |
46 | ### [Arch Linux (AUR)](https://aur.archlinux.org/packages/protonplus) (Maintained by yochananmarqos)
47 |
48 | ### [Fedora (COPR)](https://copr.fedorainfracloud.org/coprs/wehagy/protonplus/) (Maintained by wehagy)
49 |
50 | ### [NixOS (MyNixOS)](https://mynixos.com/nixpkgs/package/protonplus) (Maintained by Seth)
51 |
52 | ### [Ubuntu (Pacstall)](https://pacstall.dev/packages/protonplus) (Maintained by xdavius)
53 |
54 | ### [openSUSE](https://software.opensuse.org/package/ProtonPlus) (Maintained by rrahl0)
55 |
56 | ## 🏗️ Building from source
57 |
58 | **Requirements**
59 |
60 | - [git](https://github.com/git/git)
61 | - [ninja](https://github.com/ninja-build/ninja)
62 | - [meson >= 1.0.0](https://github.com/mesonbuild/meson)
63 | - [gtk4](https://gitlab.gnome.org/GNOME/gtk/)
64 | - [libadwaita >= 1.5](https://gitlab.gnome.org/GNOME/libadwaita)
65 | - [json-glib](https://gitlab.gnome.org/GNOME/json-glib)
66 | - [libsoup](https://gitlab.gnome.org/GNOME/libsoup)
67 | - [libarchive](https://github.com/libarchive/libarchive)
68 | - [desktop-file-utils](https://gitlab.freedesktop.org/xdg/desktop-file-utils)
69 | - [libgee](https://gitlab.gnome.org/GNOME/libgee)
70 |
71 |
72 | Linux
73 |
74 | 1. Install all dependencies (I am on Fedora, so for you this line might be different)
75 | ```bash
76 | sudo dnf install \
77 | git \
78 | gettext \
79 | 'meson >= 1.0.0'\
80 | vala \
81 | desktop-file-utils \
82 | libappstream-glib \
83 | 'pkgconfig(gee-0.8)' \
84 | 'pkgconfig(glib-2.0)' \
85 | 'pkgconfig(gtk4)' \
86 | 'pkgconfig(json-glib-1.0)' \
87 | 'pkgconfig(libadwaita-1) >= 1.5' \
88 | 'pkgconfig(libarchive)' \
89 | 'pkgconfig(libsoup-3.0)'
90 | ```
91 |
92 | 2. Clone the GitHub repo and change to repo directory
93 | ```bash
94 | git clone https://github.com/Vysp3r/ProtonPlus.git && \
95 | cd ProtonPlus
96 | ```
97 |
98 | 3. Build the local source code as a native application
99 | ```bash
100 | ./scripts/build-native.sh
101 |
102 | # Alternative: Runs application after the build.
103 | ./scripts/build-native.sh run
104 | ```
105 |
106 | 4. (Optional) Install the application
107 | ```bash
108 | cd build-native
109 | ninja install
110 | ```
111 |
112 | 5. Run the application
113 | ```bash
114 | cd src && \
115 | ./com.vysp3r.ProtonPlus
116 | ```
117 |
118 |
119 |
120 | Linux (Flatpak Builder)
121 |
122 | 1. Install all dependencies (I am on Fedora, so for you this line might be different)
123 | ```bash
124 | sudo dnf install \
125 | git \
126 | flatpak
127 | ```
128 |
129 | 2. Add the flathub repo to your system if not added before
130 | ```bash
131 | flatpak --if-not-exists remote-add \
132 | flathub https://flathub.org/repo/flathub.flatpakrepo
133 | ```
134 |
135 | 3. Install the necessary runtimes and build tools for Flatpak
136 | ```bash
137 | flatpak install \
138 | runtime/org.gnome.Sdk/x86_64/48 \
139 | runtime/org.gnome.Platform/x86_64/48 \
140 | runtime/org.freedesktop.Sdk.Extension.vala/x86_64/24.08 \
141 | org.flatpak.Builder
142 | ```
143 |
144 | 4. Clone the GitHub repo and change to repo directory
145 | ```bash
146 | git clone https://github.com/Vysp3r/ProtonPlus.git && \
147 | cd ProtonPlus
148 | ```
149 |
150 | 5. Build the local source code as a Flatpak and install for the current user
151 | ```bash
152 | ./scripts/build-local.sh
153 |
154 | # Alternative: Runs application after the build.
155 | ./scripts/build-local.sh run
156 | ```
157 |
158 | 6. Run the application
159 | ```bash
160 | flatpak --user run \
161 | com.vysp3r.ProtonPlus
162 | ```
163 |
164 |
165 | ## 🌐 Translate
166 |
167 | **You can translate ProtonPlus on [Weblate](https://hosted.weblate.org/projects/protonplus/protonplus/) or by modifying the files directly**
168 |
169 | ## 🙌 Contribute
170 |
171 | **Please read our [Contribution Guidelines](/CONTRIBUTING.md)**
172 |
173 | All contributions are highly appreciated.
174 |
175 | ## ✨️ Contributors
176 |
177 | [](https://github.com/Vysp3r/ProtonPlus/graphs/contributors)
178 |
--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------
1 | # Security Policy
2 |
3 | ## Supported Versions
4 |
5 | All versions are currently supported!
6 |
7 | ## Reporting a Vulnerability
8 |
9 | To report a vulnerability, email me at dev@vysp3r.com. Do not create an issue for that!
10 |
--------------------------------------------------------------------------------
/com.vysp3r.ProtonPlus.local.yml:
--------------------------------------------------------------------------------
1 | id: com.vysp3r.ProtonPlus
2 | runtime: org.gnome.Platform
3 | runtime-version: '48'
4 | sdk: org.gnome.Sdk
5 | sdk-extensions:
6 | - org.freedesktop.Sdk.Extension.vala
7 | command: protonplus
8 | finish-args:
9 | - --device=dri
10 | - --share=ipc
11 | - --share=network
12 | - --socket=fallback-x11
13 | - --socket=wayland
14 | # Host-spawn access is needed to check if host contains dependencies,
15 | # and to execute various compatibility tool installers on the host.
16 | - --talk-name=org.freedesktop.Flatpak
17 | # Required GNOME/GTK permissions.
18 | - --talk-name=org.gtk.vfs.*
19 | - --filesystem=xdg-run/gvfsd
20 | # Home is required due to "~/stl" installations on Steam Deck.
21 | - --filesystem=home
22 | # Request access to supported Flatpak apps (they are not included by "home").
23 | - --filesystem=~/.var/app/com.heroicgameslauncher.hgl/config/heroic
24 | - --filesystem=~/.var/app/com.usebottles.bottles/data/bottles
25 | - --filesystem=~/.var/app/com.valvesoftware.Steam/data/Steam
26 | - --filesystem=~/.var/app/net.lutris.Lutris/data/lutris
27 | build-options:
28 | append-path: /usr/lib/sdk/vala/bin
29 | prepend-ld-library-path: /usr/lib/sdk/vala/lib
30 | cleanup:
31 | - /include
32 | - /lib/pkgconfig
33 | - /share/pkgconfig
34 | - /share/aclocal
35 | - /man
36 | - /share/man
37 | - /share/gtk-doc
38 | - '*.la'
39 | - '*.a'
40 | modules:
41 | - name: ProtonPlus
42 | builddir: true
43 | buildsystem: meson
44 | sources:
45 | - type: dir
46 | path: .
47 |
--------------------------------------------------------------------------------
/com.vysp3r.ProtonPlus.yml:
--------------------------------------------------------------------------------
1 | id: com.vysp3r.ProtonPlus
2 | runtime: org.gnome.Platform
3 | runtime-version: '48'
4 | sdk: org.gnome.Sdk
5 | sdk-extensions:
6 | - org.freedesktop.Sdk.Extension.vala
7 | command: protonplus
8 | finish-args:
9 | - --device=dri
10 | - --share=ipc
11 | - --share=network
12 | - --socket=fallback-x11
13 | - --socket=wayland
14 | # Host-spawn access is needed to check if host contains dependencies,
15 | # and to execute various compatibility tool installers on the host.
16 | - --talk-name=org.freedesktop.Flatpak
17 | # Required GNOME/GTK permissions.
18 | - --talk-name=org.gtk.vfs.*
19 | - --filesystem=xdg-run/gvfsd
20 | # Home is required due to "~/stl" installations on Steam Deck.
21 | - --filesystem=home
22 | # Request access to supported Flatpak apps (they are not included by "home").
23 | - --filesystem=~/.var/app/com.heroicgameslauncher.hgl/config/heroic
24 | - --filesystem=~/.var/app/com.usebottles.bottles/data/bottles
25 | - --filesystem=~/.var/app/com.valvesoftware.Steam/data/Steam
26 | - --filesystem=~/.var/app/net.lutris.Lutris/data/lutris
27 | build-options:
28 | append-path: /usr/lib/sdk/vala/bin
29 | prepend-ld-library-path: /usr/lib/sdk/vala/lib
30 | cleanup:
31 | - /include
32 | - /lib/pkgconfig
33 | - /man
34 | - /share/gtk-doc
35 | - /share/man
36 | - /share/pkgconfig
37 | - /share/vala
38 | - '*.la'
39 | - '*.a'
40 | modules:
41 | - name: ProtonPlus
42 | builddir: true
43 | buildsystem: meson
44 | sources:
45 | - type: git
46 | url: https://github.com/Vysp3r/ProtonPlus.git
47 | tag: v0.4.31
48 | x-checker-data:
49 | type: git
50 | tag-pattern: ^v(\d+\.\d+\.\d+(?:-[0-9A-Za-z.\-]+)?)$
51 | version-scheme: semantic
52 | is-main-source: true
53 |
--------------------------------------------------------------------------------
/data/com.vysp3r.ProtonPlus.desktop.in:
--------------------------------------------------------------------------------
1 | [Desktop Entry]
2 | Name=ProtonPlus
3 | Exec=protonplus
4 | Icon=com.vysp3r.ProtonPlus
5 | Terminal=false
6 | Type=Application
7 | Categories=Game;Utility;
8 | StartupNotify=true
9 |
--------------------------------------------------------------------------------
/data/com.vysp3r.ProtonPlus.gschema.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 950
6 |
7 |
8 | 600
9 |
10 |
11 | false
12 |
13 |
14 | false
15 |
16 |
17 |
--------------------------------------------------------------------------------
/data/css/css.gresource.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | style.css
5 |
6 |
--------------------------------------------------------------------------------
/data/css/meson.build:
--------------------------------------------------------------------------------
1 | css_gresource = gnome.compile_resources(
2 | 'gresource_css',
3 | 'css.gresource.xml'
4 | )
--------------------------------------------------------------------------------
/data/css/style.css:
--------------------------------------------------------------------------------
1 | .sidebar-row {
2 | padding: 7px;
3 | }
4 |
5 | .dialog-list {
6 | background: transparent;
7 | }
8 |
9 | .dialog {
10 | padding: 10px;
11 | }
--------------------------------------------------------------------------------
/data/icons/circle-check.svg:
--------------------------------------------------------------------------------
1 |
2 |
20 |
22 |
40 |
45 |
49 |
53 |
54 |
--------------------------------------------------------------------------------
/data/icons/circle-chevron-up.svg:
--------------------------------------------------------------------------------
1 |
2 |
20 |
22 |
40 |
45 |
49 |
53 |
54 |
--------------------------------------------------------------------------------
/data/icons/dots.svg:
--------------------------------------------------------------------------------
1 |
2 |
20 |
22 |
40 |
45 |
49 |
53 |
57 |
58 |
--------------------------------------------------------------------------------
/data/icons/download.svg:
--------------------------------------------------------------------------------
1 |
2 |
20 |
22 |
40 |
45 |
49 |
53 |
57 |
58 |
--------------------------------------------------------------------------------
/data/icons/icons.gresource.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | circle-check.svg
5 | circle-chevron-up.svg
6 | trash.svg
7 | download.svg
8 | x.svg
9 | info-circle.svg
10 | dots.svg
11 | world-www.svg
12 | journal-text.svg
13 |
14 |
--------------------------------------------------------------------------------
/data/icons/info-circle.svg:
--------------------------------------------------------------------------------
1 |
2 |
20 |
22 |
40 |
45 |
49 |
53 |
57 |
58 |
--------------------------------------------------------------------------------
/data/icons/journal-text.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/data/icons/meson.build:
--------------------------------------------------------------------------------
1 | icons_gresource = gnome.compile_resources(
2 | 'gresource_icons',
3 | 'icons.gresource.xml'
4 | )
--------------------------------------------------------------------------------
/data/icons/trash.svg:
--------------------------------------------------------------------------------
1 |
2 |
20 |
22 |
40 |
45 |
49 |
53 |
57 |
61 |
65 |
66 |
--------------------------------------------------------------------------------
/data/icons/world-www.svg:
--------------------------------------------------------------------------------
1 |
2 |
20 |
22 |
40 |
45 |
49 |
53 |
57 |
61 |
65 |
69 |
73 |
77 |
81 |
82 |
--------------------------------------------------------------------------------
/data/icons/x.svg:
--------------------------------------------------------------------------------
1 |
2 |
20 |
22 |
40 |
45 |
49 |
53 |
54 |
--------------------------------------------------------------------------------
/data/images/images.gresource.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | launchers/bottles.png
5 | launchers/hgl.png
6 | launchers/lutris.png
7 | launchers/steam.png
8 |
9 |
--------------------------------------------------------------------------------
/data/images/launchers/bottles.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Vysp3r/ProtonPlus/eb67d7c33cf33d4ded407496caeb37f961b49944/data/images/launchers/bottles.png
--------------------------------------------------------------------------------
/data/images/launchers/hgl.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Vysp3r/ProtonPlus/eb67d7c33cf33d4ded407496caeb37f961b49944/data/images/launchers/hgl.png
--------------------------------------------------------------------------------
/data/images/launchers/lutris.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Vysp3r/ProtonPlus/eb67d7c33cf33d4ded407496caeb37f961b49944/data/images/launchers/lutris.png
--------------------------------------------------------------------------------
/data/images/launchers/steam.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Vysp3r/ProtonPlus/eb67d7c33cf33d4ded407496caeb37f961b49944/data/images/launchers/steam.png
--------------------------------------------------------------------------------
/data/images/meson.build:
--------------------------------------------------------------------------------
1 | images_gresource = gnome.compile_resources(
2 | 'gresource_images',
3 | 'images.gresource.xml'
4 | )
--------------------------------------------------------------------------------
/data/logo/ProtonPlus.xcf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Vysp3r/ProtonPlus/eb67d7c33cf33d4ded407496caeb37f961b49944/data/logo/ProtonPlus.xcf
--------------------------------------------------------------------------------
/data/logo/icons/hicolor/128x128/apps/com.vysp3r.ProtonPlus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Vysp3r/ProtonPlus/eb67d7c33cf33d4ded407496caeb37f961b49944/data/logo/icons/hicolor/128x128/apps/com.vysp3r.ProtonPlus.png
--------------------------------------------------------------------------------
/data/logo/icons/hicolor/16x16/apps/com.vysp3r.ProtonPlus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Vysp3r/ProtonPlus/eb67d7c33cf33d4ded407496caeb37f961b49944/data/logo/icons/hicolor/16x16/apps/com.vysp3r.ProtonPlus.png
--------------------------------------------------------------------------------
/data/logo/icons/hicolor/256x256/apps/com.vysp3r.ProtonPlus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Vysp3r/ProtonPlus/eb67d7c33cf33d4ded407496caeb37f961b49944/data/logo/icons/hicolor/256x256/apps/com.vysp3r.ProtonPlus.png
--------------------------------------------------------------------------------
/data/logo/icons/hicolor/32x32/apps/com.vysp3r.ProtonPlus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Vysp3r/ProtonPlus/eb67d7c33cf33d4ded407496caeb37f961b49944/data/logo/icons/hicolor/32x32/apps/com.vysp3r.ProtonPlus.png
--------------------------------------------------------------------------------
/data/logo/icons/hicolor/48x48/apps/com.vysp3r.ProtonPlus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Vysp3r/ProtonPlus/eb67d7c33cf33d4ded407496caeb37f961b49944/data/logo/icons/hicolor/48x48/apps/com.vysp3r.ProtonPlus.png
--------------------------------------------------------------------------------
/data/logo/icons/hicolor/512x512/apps/com.vysp3r.ProtonPlus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Vysp3r/ProtonPlus/eb67d7c33cf33d4ded407496caeb37f961b49944/data/logo/icons/hicolor/512x512/apps/com.vysp3r.ProtonPlus.png
--------------------------------------------------------------------------------
/data/logo/icons/hicolor/64x64/apps/com.vysp3r.ProtonPlus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Vysp3r/ProtonPlus/eb67d7c33cf33d4ded407496caeb37f961b49944/data/logo/icons/hicolor/64x64/apps/com.vysp3r.ProtonPlus.png
--------------------------------------------------------------------------------
/data/meson.build:
--------------------------------------------------------------------------------
1 | subdir('ui')
2 | subdir('css')
3 | subdir('icons')
4 | subdir('images')
5 |
6 | install_subdir(
7 | join_paths('logo', 'icons'),
8 | install_dir: join_paths(get_option('prefix'), get_option('datadir'), 'icons'),
9 | strip_directory: true
10 | )
11 |
12 | desktop_file = i18n.merge_file(
13 | input: 'com.vysp3r.ProtonPlus.desktop.in',
14 | output: 'com.vysp3r.ProtonPlus.desktop',
15 | type: 'desktop',
16 | po_dir: '../po',
17 | install: true,
18 | install_dir: join_paths(get_option('datadir'), 'applications')
19 | )
20 |
21 | desktop_utils = find_program('desktop-file-validate', required: false)
22 | if desktop_utils.found()
23 | test('Validate desktop file', desktop_utils, args: [desktop_file])
24 | endif
25 |
26 | appstream_file = i18n.merge_file(
27 | input: 'com.vysp3r.ProtonPlus.metainfo.xml.in',
28 | output: 'com.vysp3r.ProtonPlus.metainfo.xml',
29 | po_dir: '../po',
30 | install: true,
31 | install_dir: join_paths(get_option('datadir'), 'metainfo')
32 | )
33 |
34 | appstream_util = find_program('appstream-util', required: false)
35 | if appstream_util.found()
36 | test('Validate appstream file', appstream_util, args: ['validate-relax', '--nonet', appstream_file])
37 | endif
38 |
39 | install_data('com.vysp3r.ProtonPlus.gschema.xml',
40 | install_dir: join_paths(get_option('datadir'), 'glib-2.0/schemas')
41 | )
42 |
43 | compile_schemas = find_program('glib-compile-schemas', required: false)
44 | if compile_schemas.found()
45 | test('Validate schema file',
46 | compile_schemas,
47 | args: ['--strict', '--dry-run', meson.current_source_dir()])
48 | endif
49 |
--------------------------------------------------------------------------------
/data/previews/Preview-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Vysp3r/ProtonPlus/eb67d7c33cf33d4ded407496caeb37f961b49944/data/previews/Preview-1.png
--------------------------------------------------------------------------------
/data/ui/gtk/help-overlay.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | True
5 |
6 |
7 | shortcuts
8 | 10
9 |
10 |
11 | General
12 |
13 |
14 | Show Shortcuts
15 | win.show-help-overlay
16 |
17 |
18 |
19 |
20 | Quit
21 | app.quit
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/data/ui/meson.build:
--------------------------------------------------------------------------------
1 | ui_gresource = gnome.compile_resources(
2 | 'ui-resource',
3 | 'ui.gresource.xml'
4 | )
5 |
--------------------------------------------------------------------------------
/data/ui/ui.gresource.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | gtk/help-overlay.ui
5 |
6 |
7 |
--------------------------------------------------------------------------------
/meson.build:
--------------------------------------------------------------------------------
1 | project(
2 | 'com.vysp3r.ProtonPlus', ['c', 'vala'],
3 | version: '0.4.31',
4 | meson_version: '>= 1.0.0',
5 | default_options: [ 'warning_level=2', 'werror=false', ],
6 | )
7 |
8 | i18n = import('i18n')
9 | gnome = import('gnome')
10 | valac = meson.get_compiler('vala')
11 |
12 | src_dir = meson.project_source_root() / 'src'
13 |
14 | config_h = configuration_data()
15 | config_h.set_quoted('APP_NAME', meson.project_name().split('.')[2])
16 | config_h.set_quoted('APP_ID', meson.project_name())
17 | config_h.set_quoted('APP_VERSION', meson.project_version())
18 | config_h.set_quoted('LOCALE_DIR', join_paths (get_option('prefix'), get_option('localedir')))
19 | config_h.set_quoted('RESOURCE_BASE', '/com/vysp3r/ProtonPlus')
20 | configure_file(output : 'config.h', configuration : config_h)
21 |
22 | config_dep = valac.find_library ('config', dirs: src_dir)
23 | config_inc = include_directories('.')
24 |
25 | add_global_arguments('-DGETTEXT_PACKAGE="@0@"'.format(meson.project_name()), language: 'c')
26 |
27 | subdir('data')
28 | subdir('src')
29 | subdir('po')
30 |
31 | gnome.post_install(
32 | glib_compile_schemas: true,
33 | gtk_update_icon_cache: true,
34 | update_desktop_database: true,
35 | )
--------------------------------------------------------------------------------
/po/LINGUAS:
--------------------------------------------------------------------------------
1 | cs
2 | de
3 | es
4 | fr
5 | it
6 | ru
7 | id
8 | pt
9 | zh
10 | be
11 | fi
12 | pl
13 | sv
14 | zh_TW
--------------------------------------------------------------------------------
/po/POTFILES:
--------------------------------------------------------------------------------
1 | src/widgets/status-box.vala
2 | src/widgets/sidebar.vala
3 | src/widgets/info-box.vala
4 | src/widgets/description-dialog.vala
5 | src/widgets/busy-dialog.vala
6 | src/widgets/release-row.vala
7 | src/widgets/runner-row.vala
8 | src/widgets/runner-group.vala
9 | src/widgets/launcher-box.vala
10 | src/widgets/load-more-row.vala
11 | src/widgets/window.vala
12 | src/widgets/application.vala
13 | src/widgets/release-rows/basic.vala
14 | src/widgets/release-rows/steamtinkerlaunch.vala
15 | src/widgets/busy-dialogs/install-dialog.vala
16 | src/widgets/busy-dialogs/remove-dialog.vala
17 | src/widgets/busy-dialogs/upgrade-dialog.vala
18 | src/models/release.vala
19 | src/models/group.vala
20 | src/models/parameters.vala
21 | src/models/launcher.vala
22 | src/models/runner.vala
23 | src/models/launchers/bottles.vala
24 | src/models/launchers/hgl.vala
25 | src/models/launchers/lutris.vala
26 | src/models/launchers/steam.vala
27 | src/models/runners/basic.vala
28 | src/models/runners/github.vala
29 | src/models/runners/github-action.vala
30 | src/models/runners/gitlab.vala
31 | src/models/runners/boxtron.vala
32 | src/models/runners/dxvk-doitsujin.vala
33 | src/models/runners/dxvk-sarek.vala
34 | src/models/runners/dxvk-async-sarek.vala
35 | src/models/runners/dxvk-gpl-async-ph42on.vala
36 | src/models/runners/kron4ek-wine-builds-staging-tkg.vala
37 | src/models/runners/kron4ek-wine-builds-staging.vala
38 | src/models/runners/kron4ek-wine-builds-vanilla.vala
39 | src/models/runners/luxtorpeda.vala
40 | src/models/runners/northstar-proton.vala
41 | src/models/runners/proton-ge-rstp.vala
42 | src/models/runners/proton-ge.vala
43 | src/models/runners/proton-tkg.vala
44 | src/models/runners/roberta.vala
45 | src/models/runners/proton-cachyos.vala
46 | src/models/runners/proton-em.vala
47 | src/models/runners/proton-sarek.vala
48 | src/models/runners/proton-sarek-async.vala
49 | src/models/runners/vkd3d-lutris.vala
50 | src/models/runners/vkd3d-proton.vala
51 | src/models/runners/other.vala
52 | src/models/runners/steamtinkerlaunch.vala
53 | src/models/releases/basic.vala
54 | src/models/releases/basic.vala
55 | src/models/releases/github-action.vala
56 | src/models/releases/upgrade.vala
57 | src/models/releases/steamtinkerlaunch.vala
58 | src/utils/filesystem.vala
59 | src/utils/parser.vala
60 | src/utils/web.vala
61 | src/utils/system.vala
62 | src/main.vala
--------------------------------------------------------------------------------
/po/com.vysp3r.ProtonPlus.pot:
--------------------------------------------------------------------------------
1 | # SOME DESCRIPTIVE TITLE.
2 | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
3 | # This file is distributed under the same license as the com.vysp3r.ProtonPlus package.
4 | # FIRST AUTHOR , YEAR.
5 | #
6 | #, fuzzy
7 | msgid ""
8 | msgstr ""
9 | "Project-Id-Version: com.vysp3r.ProtonPlus\n"
10 | "Report-Msgid-Bugs-To: \n"
11 | "POT-Creation-Date: 2025-05-25 18:12-0400\n"
12 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
13 | "Last-Translator: FULL NAME \n"
14 | "Language-Team: LANGUAGE \n"
15 | "Language: \n"
16 | "MIME-Version: 1.0\n"
17 | "Content-Type: text/plain; charset=CHARSET\n"
18 | "Content-Transfer-Encoding: 8bit\n"
19 |
20 | #: src/widgets/info-box.vala:16
21 | msgid "_Installed Only"
22 | msgstr ""
23 |
24 | #: src/widgets/info-box.vala:23
25 | msgid "_Keyboard Shortcuts"
26 | msgstr ""
27 |
28 | #: src/widgets/info-box.vala:24
29 | msgid "_About ProtonPlus"
30 | msgstr ""
31 |
32 | #: src/widgets/info-box.vala:31
33 | msgid "Main Menu"
34 | msgstr ""
35 |
36 | #: src/widgets/description-dialog.vala:14
37 | msgid "More information"
38 | msgstr ""
39 |
40 | #: src/widgets/description-dialog.vala:18
41 | msgid "Open"
42 | msgstr ""
43 |
44 | #: src/widgets/description-dialog.vala:22
45 | msgid "Open in your web browser"
46 | msgstr ""
47 |
48 | #: src/widgets/busy-dialog.vala:23
49 | msgid "Show/hide logs"
50 | msgstr ""
51 |
52 | #: src/widgets/busy-dialog.vala:120
53 | msgid "Closing in"
54 | msgstr ""
55 |
56 | #: src/widgets/release-row.vala:10 src/widgets/runner-group.vala:50
57 | #: src/widgets/runner-group.vala:62 src/widgets/release-rows/basic.vala:34
58 | #: src/widgets/release-rows/steamtinkerlaunch.vala:110
59 | #, c-format
60 | msgid "Delete %s"
61 | msgstr ""
62 |
63 | #: src/widgets/release-row.vala:14
64 | #, c-format
65 | msgid "Install %s"
66 | msgstr ""
67 |
68 | #: src/widgets/release-row.vala:18
69 | msgid "Show more information"
70 | msgstr ""
71 |
72 | #: src/widgets/runner-group.vala:62 src/widgets/release-rows/basic.vala:34
73 | #: src/widgets/release-rows/steamtinkerlaunch.vala:110
74 | #, c-format
75 | msgid "You're about to remove %s from your system."
76 | msgstr ""
77 |
78 | #: src/widgets/runner-group.vala:62 src/widgets/release-rows/basic.vala:34
79 | #: src/widgets/release-rows/steamtinkerlaunch.vala:110
80 | msgid "Are you sure you want this?"
81 | msgstr ""
82 |
83 | #: src/widgets/runner-group.vala:64 src/widgets/release-rows/basic.vala:36
84 | #: src/widgets/release-rows/steamtinkerlaunch.vala:114
85 | msgid "No"
86 | msgstr ""
87 |
88 | #: src/widgets/runner-group.vala:65 src/widgets/release-rows/basic.vala:37
89 | #: src/widgets/release-rows/steamtinkerlaunch.vala:115
90 | msgid "Yes"
91 | msgstr ""
92 |
93 | #: src/widgets/load-more-row.vala:8 src/widgets/load-more-row.vala:17
94 | msgid "Load more"
95 | msgstr ""
96 |
97 | #: src/widgets/window.vala:50
98 | #, c-format
99 | msgid "Welcome to %s"
100 | msgstr ""
101 |
102 | #: src/widgets/window.vala:50
103 | msgid "Install Steam, Lutris, Bottles or Heroic Games Launcher to get started."
104 | msgstr ""
105 |
106 | #: src/widgets/application.vala:78
107 | msgid "A modern compatibility tools manager for Linux."
108 | msgstr ""
109 |
110 | #: src/widgets/application.vala:84
111 | msgid "Special thanks to"
112 | msgstr ""
113 |
114 | #: src/widgets/release-rows/steamtinkerlaunch.vala:60
115 | msgid "Missing dependencies!"
116 | msgstr ""
117 |
118 | #: src/widgets/release-rows/steamtinkerlaunch.vala:60
119 | #, c-format
120 | msgid "You are missing the following dependencies for %s:"
121 | msgstr ""
122 |
123 | #: src/widgets/release-rows/steamtinkerlaunch.vala:60
124 | msgid "Installation will be canceled."
125 | msgstr ""
126 |
127 | #: src/widgets/release-rows/steamtinkerlaunch.vala:62
128 | #: src/widgets/release-rows/steamtinkerlaunch.vala:76
129 | #: src/widgets/release-rows/steamtinkerlaunch.vala:175
130 | msgid "OK"
131 | msgstr ""
132 |
133 | #: src/widgets/release-rows/steamtinkerlaunch.vala:73
134 | #, c-format
135 | msgid "Existing installation of %s"
136 | msgstr ""
137 |
138 | #: src/widgets/release-rows/steamtinkerlaunch.vala:73
139 | #, c-format
140 | msgid ""
141 | "It looks like you currently have another version of %s which was not "
142 | "installed by ProtonPlus."
143 | msgstr ""
144 |
145 | #: src/widgets/release-rows/steamtinkerlaunch.vala:73
146 | #, c-format
147 | msgid "Do you want to delete it and install %s with ProtonPlus?"
148 | msgstr ""
149 |
150 | #: src/widgets/release-rows/steamtinkerlaunch.vala:75
151 | msgid "Cancel"
152 | msgstr ""
153 |
154 | #: src/widgets/release-rows/steamtinkerlaunch.vala:108
155 | msgid "Check this to also remove your configuration files."
156 | msgstr ""
157 |
158 | #: src/widgets/release-rows/steamtinkerlaunch.vala:165
159 | #: src/widgets/release-rows/steamtinkerlaunch.vala:169
160 | #, c-format
161 | msgid "%s is not supported"
162 | msgstr ""
163 |
164 | #: src/widgets/release-rows/steamtinkerlaunch.vala:165
165 | #, c-format
166 | msgid "To install %s for the %s, please run the following command:"
167 | msgstr ""
168 |
169 | #: src/widgets/release-rows/steamtinkerlaunch.vala:169
170 | #, c-format
171 | msgid "There's currently no known way for us to install %s for the %s."
172 | msgstr ""
173 |
174 | #: src/widgets/release-rows/steamtinkerlaunch.vala:195
175 | #, c-format
176 | msgid "%s is up-to-date"
177 | msgstr ""
178 |
179 | #: src/widgets/release-rows/steamtinkerlaunch.vala:195
180 | #, c-format
181 | msgid "Update %s to the latest version"
182 | msgstr ""
183 |
184 | #: src/widgets/busy-dialogs/install-dialog.vala:6
185 | msgid "Installing"
186 | msgstr ""
187 |
188 | #: src/widgets/busy-dialogs/remove-dialog.vala:6
189 | msgid "Removing"
190 | msgstr ""
191 |
192 | #: src/widgets/busy-dialogs/upgrade-dialog.vala:6
193 | msgid "Upgrading"
194 | msgstr ""
195 |
196 | #: src/models/release.vala:31
197 | #, c-format
198 | msgid "The installation of %s has begun."
199 | msgstr ""
200 |
201 | #: src/models/release.vala:34
202 | #, c-format
203 | msgid "The removal of %s has begun."
204 | msgstr ""
205 |
206 | #: src/models/release.vala:37
207 | #, c-format
208 | msgid "The upgrade of %s has begun."
209 | msgstr ""
210 |
211 | #: src/models/release.vala:57
212 | #, c-format
213 | msgid "An unexpected error occurred while installing %s."
214 | msgstr ""
215 |
216 | #: src/models/release.vala:59
217 | #, c-format
218 | msgid "The installation of %s is complete."
219 | msgstr ""
220 |
221 | #: src/models/release.vala:79
222 | #, c-format
223 | msgid "The removal of %s is complete."
224 | msgstr ""
225 |
226 | #: src/models/release.vala:79
227 | #, c-format
228 | msgid "An unexpected error occurred while removing %s."
229 | msgstr ""
230 |
231 | #: src/models/launchers/bottles.vala:29 src/models/launchers/steam.vala:33
232 | msgid "Runners"
233 | msgstr ""
234 |
235 | #: src/models/launchers/bottles.vala:29 src/models/launchers/hgl.vala:32
236 | #: src/models/launchers/lutris.vala:36
237 | msgid "Compatibility tools for running Windows software on Linux."
238 | msgstr ""
239 |
240 | #: src/models/launchers/bottles.vala:32 src/models/launchers/lutris.vala:39
241 | msgid "Vulkan-based implementation of Direct3D 8, 9, 10 and 11 for Linux/Wine."
242 | msgstr ""
243 |
244 | #: src/models/launchers/hgl.vala:29 src/models/launchers/lutris.vala:33
245 | msgid "Compatibility tools by Valve for running Windows software on Linux."
246 | msgstr ""
247 |
248 | #: src/models/launchers/lutris.vala:42
249 | msgid ""
250 | "Variant of Wine's VKD3D which aims to implement the full Direct3D 12 API on "
251 | "top of Vulkan."
252 | msgstr ""
253 |
254 | #: src/models/runners/boxtron.vala:6
255 | msgid "Steam compatibility tool for running DOS games using DOSBox for Linux."
256 | msgstr ""
257 |
258 | #: src/models/runners/dxvk-sarek.vala:6
259 | #: src/models/runners/dxvk-async-sarek.vala:6
260 | msgid "DXVK Builds that work with pre-Vulkan 1.3 versions"
261 | msgstr ""
262 |
263 | #: src/models/runners/kron4ek-wine-builds-staging-tkg.vala:7
264 | msgid "Wine build with the Staging patchset and many other useful patches."
265 | msgstr ""
266 |
267 | #: src/models/runners/kron4ek-wine-builds-staging.vala:7
268 | msgid "Wine build with the Staging patchset."
269 | msgstr ""
270 |
271 | #: src/models/runners/kron4ek-wine-builds-vanilla.vala:7
272 | msgid "Wine build compiled from the official WineHQ sources."
273 | msgstr ""
274 |
275 | #: src/models/runners/luxtorpeda.vala:6
276 | msgid ""
277 | "Luxtorpeda provides Linux-native game engines for certain Windows-only games."
278 | msgstr ""
279 |
280 | #: src/models/runners/northstar-proton.vala:6
281 | msgid "Custom Proton build for running the Northstar client for Titanfall 2."
282 | msgstr ""
283 |
284 | #: src/models/runners/proton-ge-rstp.vala:6
285 | msgid ""
286 | "Steam compatibility tool based on Proton-GE with additional patches to "
287 | "improve RTSP codecs for VRChat."
288 | msgstr ""
289 |
290 | #: src/models/runners/proton-ge.vala:6
291 | msgid ""
292 | "Steam compatibility tool for running Windows games with improvements over "
293 | "Valve's default Proton."
294 | msgstr ""
295 |
296 | #: src/models/runners/proton-tkg.vala:6
297 | msgid "Custom Proton build for running Windows games, based on Wine-tkg."
298 | msgstr ""
299 |
300 | #: src/models/runners/roberta.vala:6
301 | msgid ""
302 | "Steam compatibility tool for running adventure games using ScummVM for Linux."
303 | msgstr ""
304 |
305 | #: src/models/runners/proton-cachyos.vala:14
306 | msgid ""
307 | "Steam compatibility tool from the CachyOS Linux distribution for running "
308 | "Windows games with improvements over Valve's default Proton."
309 | msgstr ""
310 |
311 | #: src/models/runners/proton-em.vala:6
312 | msgid ""
313 | "Steam compatibility tool for running Windows games with improvements over "
314 | "Valve's default Proton. By Etaash Mathamsetty adding FSR4 support and wine "
315 | "wayland tweaks."
316 | msgstr ""
317 |
318 | #: src/models/runners/proton-sarek.vala:6
319 | #: src/models/runners/proton-sarek-async.vala:6
320 | #, c-format
321 | msgid ""
322 | "Steam compatibility tool based on Proton-GE with modifications for very old "
323 | "GPUs, with %s."
324 | msgstr ""
325 |
326 | #: src/models/runners/steamtinkerlaunch.vala:6
327 | msgid ""
328 | "Steam tool for easy, graphical configuration of your other compatibility "
329 | "tools for both Windows games and native Linux games."
330 | msgstr ""
331 |
332 | #: src/models/releases/basic.vala:46 src/models/releases/github-action.vala:14
333 | #: src/models/releases/steamtinkerlaunch.vala:259
334 | msgid "Downloading..."
335 | msgstr ""
336 |
337 | #: src/models/releases/basic.vala:55 src/models/releases/github-action.vala:23
338 | #: src/models/releases/steamtinkerlaunch.vala:266
339 | msgid "Extracting..."
340 | msgstr ""
341 |
342 | #: src/models/releases/basic.vala:64 src/models/releases/github-action.vala:37
343 | msgid "Renaming..."
344 | msgstr ""
345 |
346 | #: src/models/releases/basic.vala:73 src/models/releases/github-action.vala:46
347 | msgid "Running post installation script..."
348 | msgstr ""
349 |
350 | #: src/models/releases/basic.vala:84
351 | msgid "Deleting..."
352 | msgstr ""
353 |
354 | #: src/models/releases/basic.vala:91
355 | msgid "Running post removal script..."
356 | msgstr ""
357 |
358 | #: src/models/releases/upgrade.vala:8
359 | #, c-format
360 | msgid "The upgrade of %s is complete."
361 | msgstr ""
362 |
363 | #: src/models/releases/upgrade.vala:8
364 | #, c-format
365 | msgid "An unexpected error occurred while upgrading %s."
366 | msgstr ""
367 |
--------------------------------------------------------------------------------
/po/fi.po:
--------------------------------------------------------------------------------
1 | # SOME DESCRIPTIVE TITLE.
2 | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
3 | # This file is distributed under the same license as the com.vysp3r.ProtonPlus package.
4 | # Vysp3r , 2024.
5 | msgid ""
6 | msgstr ""
7 | "Project-Id-Version: com.vysp3r.ProtonPlus\n"
8 | "Report-Msgid-Bugs-To: \n"
9 | "POT-Creation-Date: 2025-05-25 18:12-0400\n"
10 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
11 | "Last-Translator: Automatically generated\n"
12 | "Language-Team: none\n"
13 | "Language: fi\n"
14 | "MIME-Version: 1.0\n"
15 | "Content-Type: text/plain; charset=UTF-8\n"
16 | "Content-Transfer-Encoding: 8bit\n"
17 |
18 | #: src/widgets/info-box.vala:16
19 | msgid "_Installed Only"
20 | msgstr ""
21 |
22 | #: src/widgets/info-box.vala:23
23 | msgid "_Keyboard Shortcuts"
24 | msgstr ""
25 |
26 | #: src/widgets/info-box.vala:24
27 | msgid "_About ProtonPlus"
28 | msgstr ""
29 |
30 | #: src/widgets/info-box.vala:31
31 | msgid "Main Menu"
32 | msgstr ""
33 |
34 | #: src/widgets/description-dialog.vala:14
35 | msgid "More information"
36 | msgstr ""
37 |
38 | #: src/widgets/description-dialog.vala:18
39 | msgid "Open"
40 | msgstr ""
41 |
42 | #: src/widgets/description-dialog.vala:22
43 | msgid "Open in your web browser"
44 | msgstr ""
45 |
46 | #: src/widgets/busy-dialog.vala:23
47 | msgid "Show/hide logs"
48 | msgstr ""
49 |
50 | #: src/widgets/busy-dialog.vala:120
51 | msgid "Closing in"
52 | msgstr ""
53 |
54 | #: src/widgets/release-row.vala:10 src/widgets/runner-group.vala:50
55 | #: src/widgets/runner-group.vala:62 src/widgets/release-rows/basic.vala:34
56 | #: src/widgets/release-rows/steamtinkerlaunch.vala:110
57 | #, c-format
58 | msgid "Delete %s"
59 | msgstr ""
60 |
61 | #: src/widgets/release-row.vala:14
62 | #, c-format
63 | msgid "Install %s"
64 | msgstr ""
65 |
66 | #: src/widgets/release-row.vala:18
67 | msgid "Show more information"
68 | msgstr ""
69 |
70 | #: src/widgets/runner-group.vala:62 src/widgets/release-rows/basic.vala:34
71 | #: src/widgets/release-rows/steamtinkerlaunch.vala:110
72 | #, c-format
73 | msgid "You're about to remove %s from your system."
74 | msgstr ""
75 |
76 | #: src/widgets/runner-group.vala:62 src/widgets/release-rows/basic.vala:34
77 | #: src/widgets/release-rows/steamtinkerlaunch.vala:110
78 | msgid "Are you sure you want this?"
79 | msgstr ""
80 |
81 | #: src/widgets/runner-group.vala:64 src/widgets/release-rows/basic.vala:36
82 | #: src/widgets/release-rows/steamtinkerlaunch.vala:114
83 | msgid "No"
84 | msgstr ""
85 |
86 | #: src/widgets/runner-group.vala:65 src/widgets/release-rows/basic.vala:37
87 | #: src/widgets/release-rows/steamtinkerlaunch.vala:115
88 | msgid "Yes"
89 | msgstr ""
90 |
91 | #: src/widgets/load-more-row.vala:8 src/widgets/load-more-row.vala:17
92 | msgid "Load more"
93 | msgstr ""
94 |
95 | #: src/widgets/window.vala:50
96 | #, c-format
97 | msgid "Welcome to %s"
98 | msgstr ""
99 |
100 | #: src/widgets/window.vala:50
101 | msgid "Install Steam, Lutris, Bottles or Heroic Games Launcher to get started."
102 | msgstr ""
103 |
104 | #: src/widgets/application.vala:78
105 | msgid "A modern compatibility tools manager for Linux."
106 | msgstr ""
107 |
108 | #: src/widgets/application.vala:84
109 | msgid "Special thanks to"
110 | msgstr ""
111 |
112 | #: src/widgets/release-rows/steamtinkerlaunch.vala:60
113 | msgid "Missing dependencies!"
114 | msgstr ""
115 |
116 | #: src/widgets/release-rows/steamtinkerlaunch.vala:60
117 | #, c-format
118 | msgid "You are missing the following dependencies for %s:"
119 | msgstr ""
120 |
121 | #: src/widgets/release-rows/steamtinkerlaunch.vala:60
122 | msgid "Installation will be canceled."
123 | msgstr ""
124 |
125 | #: src/widgets/release-rows/steamtinkerlaunch.vala:62
126 | #: src/widgets/release-rows/steamtinkerlaunch.vala:76
127 | #: src/widgets/release-rows/steamtinkerlaunch.vala:175
128 | msgid "OK"
129 | msgstr ""
130 |
131 | #: src/widgets/release-rows/steamtinkerlaunch.vala:73
132 | #, c-format
133 | msgid "Existing installation of %s"
134 | msgstr ""
135 |
136 | #: src/widgets/release-rows/steamtinkerlaunch.vala:73
137 | #, c-format
138 | msgid ""
139 | "It looks like you currently have another version of %s which was not "
140 | "installed by ProtonPlus."
141 | msgstr ""
142 |
143 | #: src/widgets/release-rows/steamtinkerlaunch.vala:73
144 | #, c-format
145 | msgid "Do you want to delete it and install %s with ProtonPlus?"
146 | msgstr ""
147 |
148 | #: src/widgets/release-rows/steamtinkerlaunch.vala:75
149 | msgid "Cancel"
150 | msgstr ""
151 |
152 | #: src/widgets/release-rows/steamtinkerlaunch.vala:108
153 | msgid "Check this to also remove your configuration files."
154 | msgstr ""
155 |
156 | #: src/widgets/release-rows/steamtinkerlaunch.vala:165
157 | #: src/widgets/release-rows/steamtinkerlaunch.vala:169
158 | #, c-format
159 | msgid "%s is not supported"
160 | msgstr ""
161 |
162 | #: src/widgets/release-rows/steamtinkerlaunch.vala:165
163 | #, c-format
164 | msgid "To install %s for the %s, please run the following command:"
165 | msgstr ""
166 |
167 | #: src/widgets/release-rows/steamtinkerlaunch.vala:169
168 | #, c-format
169 | msgid "There's currently no known way for us to install %s for the %s."
170 | msgstr ""
171 |
172 | #: src/widgets/release-rows/steamtinkerlaunch.vala:195
173 | #, c-format
174 | msgid "%s is up-to-date"
175 | msgstr ""
176 |
177 | #: src/widgets/release-rows/steamtinkerlaunch.vala:195
178 | #, c-format
179 | msgid "Update %s to the latest version"
180 | msgstr ""
181 |
182 | #: src/widgets/busy-dialogs/install-dialog.vala:6
183 | msgid "Installing"
184 | msgstr ""
185 |
186 | #: src/widgets/busy-dialogs/remove-dialog.vala:6
187 | msgid "Removing"
188 | msgstr ""
189 |
190 | #: src/widgets/busy-dialogs/upgrade-dialog.vala:6
191 | msgid "Upgrading"
192 | msgstr ""
193 |
194 | #: src/models/release.vala:31
195 | #, c-format
196 | msgid "The installation of %s has begun."
197 | msgstr ""
198 |
199 | #: src/models/release.vala:34
200 | #, c-format
201 | msgid "The removal of %s has begun."
202 | msgstr ""
203 |
204 | #: src/models/release.vala:37
205 | #, c-format
206 | msgid "The upgrade of %s has begun."
207 | msgstr ""
208 |
209 | #: src/models/release.vala:57
210 | #, c-format
211 | msgid "An unexpected error occurred while installing %s."
212 | msgstr ""
213 |
214 | #: src/models/release.vala:59
215 | #, c-format
216 | msgid "The installation of %s is complete."
217 | msgstr ""
218 |
219 | #: src/models/release.vala:79
220 | #, c-format
221 | msgid "The removal of %s is complete."
222 | msgstr ""
223 |
224 | #: src/models/release.vala:79
225 | #, c-format
226 | msgid "An unexpected error occurred while removing %s."
227 | msgstr ""
228 |
229 | #: src/models/launchers/bottles.vala:29 src/models/launchers/steam.vala:33
230 | msgid "Runners"
231 | msgstr ""
232 |
233 | #: src/models/launchers/bottles.vala:29 src/models/launchers/hgl.vala:32
234 | #: src/models/launchers/lutris.vala:36
235 | msgid "Compatibility tools for running Windows software on Linux."
236 | msgstr ""
237 |
238 | #: src/models/launchers/bottles.vala:32 src/models/launchers/lutris.vala:39
239 | msgid "Vulkan-based implementation of Direct3D 8, 9, 10 and 11 for Linux/Wine."
240 | msgstr ""
241 |
242 | #: src/models/launchers/hgl.vala:29 src/models/launchers/lutris.vala:33
243 | msgid "Compatibility tools by Valve for running Windows software on Linux."
244 | msgstr ""
245 |
246 | #: src/models/launchers/lutris.vala:42
247 | msgid ""
248 | "Variant of Wine's VKD3D which aims to implement the full Direct3D 12 API on "
249 | "top of Vulkan."
250 | msgstr ""
251 |
252 | #: src/models/runners/boxtron.vala:6
253 | msgid "Steam compatibility tool for running DOS games using DOSBox for Linux."
254 | msgstr ""
255 |
256 | #: src/models/runners/dxvk-sarek.vala:6
257 | #: src/models/runners/dxvk-async-sarek.vala:6
258 | msgid "DXVK Builds that work with pre-Vulkan 1.3 versions"
259 | msgstr ""
260 |
261 | #: src/models/runners/kron4ek-wine-builds-staging-tkg.vala:7
262 | msgid "Wine build with the Staging patchset and many other useful patches."
263 | msgstr ""
264 |
265 | #: src/models/runners/kron4ek-wine-builds-staging.vala:7
266 | msgid "Wine build with the Staging patchset."
267 | msgstr ""
268 |
269 | #: src/models/runners/kron4ek-wine-builds-vanilla.vala:7
270 | msgid "Wine build compiled from the official WineHQ sources."
271 | msgstr ""
272 |
273 | #: src/models/runners/luxtorpeda.vala:6
274 | msgid ""
275 | "Luxtorpeda provides Linux-native game engines for certain Windows-only games."
276 | msgstr ""
277 |
278 | #: src/models/runners/northstar-proton.vala:6
279 | msgid "Custom Proton build for running the Northstar client for Titanfall 2."
280 | msgstr ""
281 |
282 | #: src/models/runners/proton-ge-rstp.vala:6
283 | msgid ""
284 | "Steam compatibility tool based on Proton-GE with additional patches to "
285 | "improve RTSP codecs for VRChat."
286 | msgstr ""
287 |
288 | #: src/models/runners/proton-ge.vala:6
289 | msgid ""
290 | "Steam compatibility tool for running Windows games with improvements over "
291 | "Valve's default Proton."
292 | msgstr ""
293 |
294 | #: src/models/runners/proton-tkg.vala:6
295 | msgid "Custom Proton build for running Windows games, based on Wine-tkg."
296 | msgstr ""
297 |
298 | #: src/models/runners/roberta.vala:6
299 | msgid ""
300 | "Steam compatibility tool for running adventure games using ScummVM for Linux."
301 | msgstr ""
302 |
303 | #: src/models/runners/proton-cachyos.vala:14
304 | msgid ""
305 | "Steam compatibility tool from the CachyOS Linux distribution for running "
306 | "Windows games with improvements over Valve's default Proton."
307 | msgstr ""
308 |
309 | #: src/models/runners/proton-em.vala:6
310 | msgid ""
311 | "Steam compatibility tool for running Windows games with improvements over "
312 | "Valve's default Proton. By Etaash Mathamsetty adding FSR4 support and wine "
313 | "wayland tweaks."
314 | msgstr ""
315 |
316 | #: src/models/runners/proton-sarek.vala:6
317 | #: src/models/runners/proton-sarek-async.vala:6
318 | #, c-format
319 | msgid ""
320 | "Steam compatibility tool based on Proton-GE with modifications for very old "
321 | "GPUs, with %s."
322 | msgstr ""
323 |
324 | #: src/models/runners/steamtinkerlaunch.vala:6
325 | msgid ""
326 | "Steam tool for easy, graphical configuration of your other compatibility "
327 | "tools for both Windows games and native Linux games."
328 | msgstr ""
329 |
330 | #: src/models/releases/basic.vala:46 src/models/releases/github-action.vala:14
331 | #: src/models/releases/steamtinkerlaunch.vala:259
332 | msgid "Downloading..."
333 | msgstr ""
334 |
335 | #: src/models/releases/basic.vala:55 src/models/releases/github-action.vala:23
336 | #: src/models/releases/steamtinkerlaunch.vala:266
337 | msgid "Extracting..."
338 | msgstr ""
339 |
340 | #: src/models/releases/basic.vala:64 src/models/releases/github-action.vala:37
341 | msgid "Renaming..."
342 | msgstr ""
343 |
344 | #: src/models/releases/basic.vala:73 src/models/releases/github-action.vala:46
345 | msgid "Running post installation script..."
346 | msgstr ""
347 |
348 | #: src/models/releases/basic.vala:84
349 | msgid "Deleting..."
350 | msgstr ""
351 |
352 | #: src/models/releases/basic.vala:91
353 | msgid "Running post removal script..."
354 | msgstr ""
355 |
356 | #: src/models/releases/upgrade.vala:8
357 | #, c-format
358 | msgid "The upgrade of %s is complete."
359 | msgstr ""
360 |
361 | #: src/models/releases/upgrade.vala:8
362 | #, c-format
363 | msgid "An unexpected error occurred while upgrading %s."
364 | msgstr ""
365 |
--------------------------------------------------------------------------------
/po/meson.build:
--------------------------------------------------------------------------------
1 | i18n.gettext(
2 | meson.project_name(),
3 | preset: 'glib'
4 | )
--------------------------------------------------------------------------------
/po/zh_TW.po:
--------------------------------------------------------------------------------
1 | # SOME DESCRIPTIVE TITLE.
2 | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
3 | # This file is distributed under the same license as the com.vysp3r.ProtonPlus package.
4 | # FIRST AUTHOR , YEAR.
5 | #
6 | #, fuzzy
7 | msgid ""
8 | msgstr ""
9 | "Project-Id-Version: com.vysp3r.ProtonPlus\n"
10 | "Report-Msgid-Bugs-To: \n"
11 | "POT-Creation-Date: 2025-05-25 18:12-0400\n"
12 | "PO-Revision-Date: 2025-05-25 01:30+0800\n"
13 | "Last-Translator: nick.exe \n"
14 | "Language-Team: CodeBay.IN\n"
15 | "Language: zh_TW\n"
16 | "MIME-Version: 1.0\n"
17 | "Content-Type: text/plain; charset=UTF-8\n"
18 | "Content-Transfer-Encoding: 8bit\n"
19 | "X-Generator: Poedit 3.6\n"
20 |
21 | #: src/widgets/info-box.vala:16
22 | msgid "_Installed Only"
23 | msgstr "僅列出已安裝的(_I)"
24 |
25 | #: src/widgets/info-box.vala:23
26 | msgid "_Keyboard Shortcuts"
27 | msgstr "鍵盤捷徑鍵(_K)"
28 |
29 | #: src/widgets/info-box.vala:24
30 | msgid "_About ProtonPlus"
31 | msgstr "關於 ProtonPlus(_A)"
32 |
33 | #: src/widgets/info-box.vala:31
34 | msgid "Main Menu"
35 | msgstr "主選單"
36 |
37 | #: src/widgets/description-dialog.vala:14
38 | msgid "More information"
39 | msgstr "更多資訊"
40 |
41 | #: src/widgets/description-dialog.vala:18
42 | msgid "Open"
43 | msgstr "開啟"
44 |
45 | #: src/widgets/description-dialog.vala:22
46 | msgid "Open in your web browser"
47 | msgstr "於瀏覽器中開啟"
48 |
49 | #: src/widgets/busy-dialog.vala:23
50 | msgid "Show/hide logs"
51 | msgstr "顯示/隱藏日誌"
52 |
53 | #: src/widgets/busy-dialog.vala:120
54 | msgid "Closing in"
55 | msgstr "即將關閉..."
56 |
57 | #: src/widgets/release-row.vala:10 src/widgets/runner-group.vala:50
58 | #: src/widgets/runner-group.vala:62 src/widgets/release-rows/basic.vala:34
59 | #: src/widgets/release-rows/steamtinkerlaunch.vala:110
60 | #, c-format
61 | msgid "Delete %s"
62 | msgstr "移除 %s"
63 |
64 | #: src/widgets/release-row.vala:14
65 | #, c-format
66 | msgid "Install %s"
67 | msgstr "安裝 %s"
68 |
69 | #: src/widgets/release-row.vala:18
70 | msgid "Show more information"
71 | msgstr "顯示更多資訊"
72 |
73 | #: src/widgets/runner-group.vala:62 src/widgets/release-rows/basic.vala:34
74 | #: src/widgets/release-rows/steamtinkerlaunch.vala:110
75 | #, c-format
76 | msgid "You're about to remove %s from your system."
77 | msgstr "您即將從系統中移除 %s。"
78 |
79 | #: src/widgets/runner-group.vala:62 src/widgets/release-rows/basic.vala:34
80 | #: src/widgets/release-rows/steamtinkerlaunch.vala:110
81 | msgid "Are you sure you want this?"
82 | msgstr "您確定要繼續嗎?"
83 |
84 | #: src/widgets/runner-group.vala:64 src/widgets/release-rows/basic.vala:36
85 | #: src/widgets/release-rows/steamtinkerlaunch.vala:114
86 | msgid "No"
87 | msgstr "否"
88 |
89 | #: src/widgets/runner-group.vala:65 src/widgets/release-rows/basic.vala:37
90 | #: src/widgets/release-rows/steamtinkerlaunch.vala:115
91 | msgid "Yes"
92 | msgstr "是"
93 |
94 | #: src/widgets/load-more-row.vala:8 src/widgets/load-more-row.vala:17
95 | msgid "Load more"
96 | msgstr "載入更多"
97 |
98 | #: src/widgets/window.vala:50
99 | #, c-format
100 | msgid "Welcome to %s"
101 | msgstr "歡迎來到 %s"
102 |
103 | #: src/widgets/window.vala:50
104 | msgid "Install Steam, Lutris, Bottles or Heroic Games Launcher to get started."
105 | msgstr "請安裝 Steam、Lutris、Bottles 或 Heroic Games Launcher 以開始使用。"
106 |
107 | #: src/widgets/application.vala:78
108 | msgid "A modern compatibility tools manager for Linux."
109 | msgstr "適用於 Linux 的現代相容性工具管理程式。"
110 |
111 | #: src/widgets/application.vala:84
112 | msgid "Special thanks to"
113 | msgstr "特別感謝"
114 |
115 | #: src/widgets/release-rows/steamtinkerlaunch.vala:60
116 | msgid "Missing dependencies!"
117 | msgstr "缺少相依性工具!"
118 |
119 | #: src/widgets/release-rows/steamtinkerlaunch.vala:60
120 | #, c-format
121 | msgid "You are missing the following dependencies for %s:"
122 | msgstr "您缺少下列 %s 的相依性工具:"
123 |
124 | #: src/widgets/release-rows/steamtinkerlaunch.vala:60
125 | msgid "Installation will be canceled."
126 | msgstr "安裝將被取消。"
127 |
128 | #: src/widgets/release-rows/steamtinkerlaunch.vala:62
129 | #: src/widgets/release-rows/steamtinkerlaunch.vala:76
130 | #: src/widgets/release-rows/steamtinkerlaunch.vala:175
131 | msgid "OK"
132 | msgstr "確定"
133 |
134 | #: src/widgets/release-rows/steamtinkerlaunch.vala:73
135 | #, c-format
136 | msgid "Existing installation of %s"
137 | msgstr "已存在 %s 的安裝"
138 |
139 | #: src/widgets/release-rows/steamtinkerlaunch.vala:73
140 | #, c-format
141 | msgid ""
142 | "It looks like you currently have another version of %s which was not "
143 | "installed by ProtonPlus."
144 | msgstr "看起來您目前有另一個版本的 %s,但不是透過 ProtonPlus 安裝的。"
145 |
146 | #: src/widgets/release-rows/steamtinkerlaunch.vala:73
147 | #, c-format
148 | msgid "Do you want to delete it and install %s with ProtonPlus?"
149 | msgstr "您要移除它並使用 ProtonPlus 安裝 %s 嗎?"
150 |
151 | #: src/widgets/release-rows/steamtinkerlaunch.vala:75
152 | msgid "Cancel"
153 | msgstr "取消"
154 |
155 | #: src/widgets/release-rows/steamtinkerlaunch.vala:108
156 | msgid "Check this to also remove your configuration files."
157 | msgstr "勾選此選項也會移除設定檔。"
158 |
159 | #: src/widgets/release-rows/steamtinkerlaunch.vala:165
160 | #: src/widgets/release-rows/steamtinkerlaunch.vala:169
161 | #, c-format
162 | msgid "%s is not supported"
163 | msgstr "不支援 %s"
164 |
165 | #: src/widgets/release-rows/steamtinkerlaunch.vala:165
166 | #, c-format
167 | msgid "To install %s for the %s, please run the following command:"
168 | msgstr "若要為 %2$s 安裝 %1$s,請運行以下命令:"
169 |
170 | #: src/widgets/release-rows/steamtinkerlaunch.vala:169
171 | #, c-format
172 | msgid "There's currently no known way for us to install %s for the %s."
173 | msgstr "目前尚無已知的方法來為 %2$s 安裝 %1$s。"
174 |
175 | #: src/widgets/release-rows/steamtinkerlaunch.vala:195
176 | #, c-format
177 | msgid "%s is up-to-date"
178 | msgstr "%s 已為最新版本"
179 |
180 | #: src/widgets/release-rows/steamtinkerlaunch.vala:195
181 | #, c-format
182 | msgid "Update %s to the latest version"
183 | msgstr "更新 %s 至最新版本"
184 |
185 | #: src/widgets/busy-dialogs/install-dialog.vala:6
186 | msgid "Installing"
187 | msgstr "正在安裝"
188 |
189 | #: src/widgets/busy-dialogs/remove-dialog.vala:6
190 | msgid "Removing"
191 | msgstr "正在移除"
192 |
193 | #: src/widgets/busy-dialogs/upgrade-dialog.vala:6
194 | msgid "Upgrading"
195 | msgstr "正在更新"
196 |
197 | #: src/models/release.vala:31
198 | #, c-format
199 | msgid "The installation of %s has begun."
200 | msgstr "%s 的安裝已開始。"
201 |
202 | #: src/models/release.vala:34
203 | #, c-format
204 | msgid "The removal of %s has begun."
205 | msgstr "%s 的移除已開始。"
206 |
207 | #: src/models/release.vala:37
208 | #, c-format
209 | msgid "The upgrade of %s has begun."
210 | msgstr "%s 的更新已開始。"
211 |
212 | #: src/models/release.vala:57
213 | #, c-format
214 | msgid "An unexpected error occurred while installing %s."
215 | msgstr "安裝 %s 時發生意外錯誤。"
216 |
217 | #: src/models/release.vala:59
218 | #, c-format
219 | msgid "The installation of %s is complete."
220 | msgstr "%s 的安裝已完成。"
221 |
222 | #: src/models/release.vala:79
223 | #, c-format
224 | msgid "The removal of %s is complete."
225 | msgstr "%s 的移除已完成。"
226 |
227 | #: src/models/release.vala:79
228 | #, c-format
229 | msgid "An unexpected error occurred while removing %s."
230 | msgstr "移除 %s 時發生意外錯誤。"
231 |
232 | #: src/models/launchers/bottles.vala:29 src/models/launchers/steam.vala:33
233 | msgid "Runners"
234 | msgstr "運行器"
235 |
236 | #: src/models/launchers/bottles.vala:29 src/models/launchers/hgl.vala:32
237 | #: src/models/launchers/lutris.vala:36
238 | msgid "Compatibility tools for running Windows software on Linux."
239 | msgstr "用於在 Linux 上運行 Windows 軟體的相容性工具。"
240 |
241 | #: src/models/launchers/bottles.vala:32 src/models/launchers/lutris.vala:39
242 | msgid "Vulkan-based implementation of Direct3D 8, 9, 10 and 11 for Linux/Wine."
243 | msgstr "適用於 Linux/Wine 的,基於 Vulkan 的 Direct3D 8、9、10 和 11 的實作。"
244 |
245 | #: src/models/launchers/hgl.vala:29 src/models/launchers/lutris.vala:33
246 | msgid "Compatibility tools by Valve for running Windows software on Linux."
247 | msgstr "由 Valve 提供的,用於在 Linux 上運行 Windows 軟體的相容性工具。"
248 |
249 | #: src/models/launchers/lutris.vala:42
250 | msgid ""
251 | "Variant of Wine's VKD3D which aims to implement the full Direct3D 12 API on "
252 | "top of Vulkan."
253 | msgstr "Wine VKD3D 的特化版,旨在 Vulkan 之上實作完整的 Direct3D 12 API。"
254 |
255 | #: src/models/runners/boxtron.vala:6
256 | msgid "Steam compatibility tool for running DOS games using DOSBox for Linux."
257 | msgstr "用於使用 Linux 版 DOSBox 運行 DOS 遊戲的 Steam 相容性工具。"
258 |
259 | #: src/models/runners/dxvk-sarek.vala:6
260 | #: src/models/runners/dxvk-async-sarek.vala:6
261 | msgid "DXVK Builds that work with pre-Vulkan 1.3 versions"
262 | msgstr "適用於 Vulkan 1.3 之前的 DXVK 建構版本。"
263 |
264 | #: src/models/runners/kron4ek-wine-builds-staging-tkg.vala:7
265 | msgid "Wine build with the Staging patchset and many other useful patches."
266 | msgstr "包含 Staging 修補程式集,以及多項實用修補程式的 Wine 建構版本。"
267 |
268 | #: src/models/runners/kron4ek-wine-builds-staging.vala:7
269 | msgid "Wine build with the Staging patchset."
270 | msgstr "包含 Staging 修補程式集的 Wine 建構版本。"
271 |
272 | #: src/models/runners/kron4ek-wine-builds-vanilla.vala:7
273 | msgid "Wine build compiled from the official WineHQ sources."
274 | msgstr "從官方 WineHQ 原始碼編譯的 Wine 建構版本。"
275 |
276 | #: src/models/runners/luxtorpeda.vala:6
277 | msgid ""
278 | "Luxtorpeda provides Linux-native game engines for certain Windows-only games."
279 | msgstr "Luxtorpeda 能為特定 Windows 專屬遊戲提供 Linux 原生遊戲引擎。"
280 |
281 | #: src/models/runners/northstar-proton.vala:6
282 | msgid "Custom Proton build for running the Northstar client for Titanfall 2."
283 | msgstr "用於運行 Titanfall 2 Northstar 用戶端的自訂 Proton 建構版本。"
284 |
285 | #: src/models/runners/proton-ge-rstp.vala:6
286 | msgid ""
287 | "Steam compatibility tool based on Proton-GE with additional patches to "
288 | "improve RTSP codecs for VRChat."
289 | msgstr ""
290 | "基於 Proton-GE 的 Steam 相容性工具,包含額外的修補程式以改善 VRChat 的 RTSP "
291 | "編解碼器。"
292 |
293 | #: src/models/runners/proton-ge.vala:6
294 | msgid ""
295 | "Steam compatibility tool for running Windows games with improvements over "
296 | "Valve's default Proton."
297 | msgstr ""
298 | "用於運行 Windows 遊戲的 Steam 相容性工具,並在 Valve 預設的 Proton 上做了改"
299 | "進。"
300 |
301 | #: src/models/runners/proton-tkg.vala:6
302 | msgid "Custom Proton build for running Windows games, based on Wine-tkg."
303 | msgstr "基於 Wine-tkg 的,用於運行 Windows 遊戲的自訂 Proton 建構版本。"
304 |
305 | #: src/models/runners/roberta.vala:6
306 | msgid ""
307 | "Steam compatibility tool for running adventure games using ScummVM for Linux."
308 | msgstr "用於使用 Linux 版 ScummVM 運行冒險遊戲的 Steam 相容性工具。"
309 |
310 | #: src/models/runners/proton-cachyos.vala:14
311 | msgid ""
312 | "Steam compatibility tool from the CachyOS Linux distribution for running "
313 | "Windows games with improvements over Valve's default Proton."
314 | msgstr ""
315 | "CachyOS Linux 發行版的 Steam 相容性工具,用於運行 Windows 遊戲,並在 Valve 預"
316 | "設的 Proton 上做了改進。"
317 |
318 | #: src/models/runners/proton-em.vala:6
319 | msgid ""
320 | "Steam compatibility tool for running Windows games with improvements over "
321 | "Valve's default Proton. By Etaash Mathamsetty adding FSR4 support and wine "
322 | "wayland tweaks."
323 | msgstr ""
324 | "用於運行 Windows 遊戲的 Steam 相容性工具,並在 Valve 預設的 Proton 上做了改"
325 | "進。由 Etaash Mathamsetty 新增 FSR4 支援和 Wine Wayland 調整。"
326 |
327 | #: src/models/runners/proton-sarek.vala:6
328 | #: src/models/runners/proton-sarek-async.vala:6
329 | #, c-format
330 | msgid ""
331 | "Steam compatibility tool based on Proton-GE with modifications for very old "
332 | "GPUs, with %s."
333 | msgstr ""
334 | "基於 Proton-GE 的 Steam 相容性工具,包含對非常舊的 GPU 進行的修改,並包含 "
335 | "%s。"
336 |
337 | #: src/models/runners/steamtinkerlaunch.vala:6
338 | msgid ""
339 | "Steam tool for easy, graphical configuration of your other compatibility "
340 | "tools for both Windows games and native Linux games."
341 | msgstr ""
342 | "讓您能以圖形介面輕鬆設定的 Steam 工具,專門調整用於 Windows 遊戲和原生 Linux "
343 | "遊戲的各種相容性工具。"
344 |
345 | #: src/models/releases/basic.vala:46 src/models/releases/github-action.vala:14
346 | #: src/models/releases/steamtinkerlaunch.vala:259
347 | msgid "Downloading..."
348 | msgstr "正在下載..."
349 |
350 | #: src/models/releases/basic.vala:55 src/models/releases/github-action.vala:23
351 | #: src/models/releases/steamtinkerlaunch.vala:266
352 | msgid "Extracting..."
353 | msgstr "正在解壓縮..."
354 |
355 | #: src/models/releases/basic.vala:64 src/models/releases/github-action.vala:37
356 | msgid "Renaming..."
357 | msgstr "正在重新命名..."
358 |
359 | #: src/models/releases/basic.vala:73 src/models/releases/github-action.vala:46
360 | msgid "Running post installation script..."
361 | msgstr "正在運行安裝後的腳本..."
362 |
363 | #: src/models/releases/basic.vala:84
364 | msgid "Deleting..."
365 | msgstr "正在移除..."
366 |
367 | #: src/models/releases/basic.vala:91
368 | msgid "Running post removal script..."
369 | msgstr "正在運行移除後的腳本..."
370 |
371 | #: src/models/releases/upgrade.vala:8
372 | #, c-format
373 | msgid "The upgrade of %s is complete."
374 | msgstr "%s 的更新已完成。"
375 |
376 | #: src/models/releases/upgrade.vala:8
377 | #, c-format
378 | msgid "An unexpected error occurred while upgrading %s."
379 | msgstr "更新 %s 時發生意外錯誤。"
380 |
--------------------------------------------------------------------------------
/scripts/build-flathub.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -ex
4 |
5 | SCRIPT_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
6 | cd "${SCRIPT_DIR}/.."
7 |
8 | BUILD_VARIANT="flathub"
9 | BUILD_MANIFEST="com.vysp3r.ProtonPlus.yml"
10 | BUILD_DIR="build-flatpak/${BUILD_VARIANT}/build"
11 | BUILD_OSTREE_REPO="build-flatpak/${BUILD_VARIANT}/repo"
12 | flatpak run org.flatpak.Builder --verbose \
13 | --sandbox --force-clean --ccache --user --install \
14 | "${BUILD_DIR}" \
15 | "${BUILD_MANIFEST}"
16 |
17 | if [[ "$1" == "run" ]]; then
18 | flatpak run --user com.vysp3r.ProtonPlus
19 | fi
20 |
--------------------------------------------------------------------------------
/scripts/build-local.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -ex
4 |
5 | SCRIPT_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
6 | cd "${SCRIPT_DIR}/.."
7 |
8 | BUILD_VARIANT="local"
9 | BUILD_MANIFEST="com.vysp3r.ProtonPlus.local.yml"
10 | BUILD_DIR="build-flatpak/${BUILD_VARIANT}/build"
11 | BUILD_OSTREE_REPO="build-flatpak/${BUILD_VARIANT}/repo"
12 | flatpak run org.flatpak.Builder --verbose \
13 | --sandbox --force-clean --ccache --user --install \
14 | "${BUILD_DIR}" \
15 | "${BUILD_MANIFEST}"
16 |
17 | if [[ "$1" == "run" ]]; then
18 | flatpak run --user com.vysp3r.ProtonPlus
19 | fi
20 |
--------------------------------------------------------------------------------
/scripts/build-native.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -e
4 |
5 | SCRIPT_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
6 | cd "${SCRIPT_DIR}/.."
7 |
8 | BUILD_DIR="build-native"
9 | meson "${BUILD_DIR}" --wipe --prefix=/usr
10 | cd "${BUILD_DIR}"
11 | ninja
12 |
13 | if [[ "$1" == "run" ]]; then
14 | cd src
15 | ./com.vysp3r.ProtonPlus
16 | fi
17 |
--------------------------------------------------------------------------------
/scripts/flathub-linter.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -ex
4 |
5 | SCRIPT_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
6 | cd "${SCRIPT_DIR}/.."
7 |
8 | # We must perform a Flatpak build *and* export to a ostree "repo" directory.
9 | # NOTE: We will perform a LOCAL build so that we check the LOCAL manifest.
10 | # NOTE: We don't trigger INSTALL in this case, since we're just linting.
11 | BUILD_VARIANT="local"
12 | BUILD_MANIFEST="com.vysp3r.ProtonPlus.local.yml"
13 | BUILD_DIR="build-flatpak/${BUILD_VARIANT}/build"
14 | BUILD_OSTREE_REPO="build-flatpak/${BUILD_VARIANT}/repo"
15 | flatpak run org.flatpak.Builder --verbose \
16 | --sandbox --force-clean --ccache \
17 | --repo="${BUILD_OSTREE_REPO}" \
18 | "${BUILD_DIR}" \
19 | "${BUILD_MANIFEST}"
20 |
21 | # Allow command failures after this point, since linters may exit with errors.
22 | set +e
23 |
24 | # Now we can run the Flathub linters.
25 | echo -e "\n\n\n\nLinter Results:\n"
26 | flatpak run --command=flatpak-builder-lint org.flatpak.Builder manifest "${BUILD_MANIFEST}"
27 | flatpak run --command=flatpak-builder-lint org.flatpak.Builder appstream "${BUILD_DIR}/export/share/metainfo/com.vysp3r.ProtonPlus.metainfo.xml"
28 | flatpak run --command=flatpak-builder-lint org.flatpak.Builder repo "${BUILD_OSTREE_REPO}"
29 |
30 | set +x
31 | echo -e "\nSome linter errors regarding external icons, screenshots or screenshot files may happen in a local build but not on Flathub. Those can be safely ignored."
32 | echo -e "\nAlways ignore the following linter errors:\n- \"appid-filename-mismatch: com.vysp3r.ProtonPlus.local\" (because we perform linting of the local development source code)\n- \"finish-args-flatpak-spawn-access\" (it's the only way for us to install Runners on the Host)"
33 |
--------------------------------------------------------------------------------
/scripts/generate-icons.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -e
4 |
5 | SCRIPT_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
6 | cd "${SCRIPT_DIR}/.."
7 |
8 | SVG_DIR="data/logo"
9 | EXPORT_DIR="data/logo/icons/hicolor"
10 | ICON_SIZES=(512 256 128 64 48 32 16)
11 |
12 | for svg_file in "${SVG_DIR}"/*.svg; do
13 | svg_name="$(basename "${svg_file}")"
14 |
15 | for size in "${ICON_SIZES[@]}"; do
16 | echo "${svg_name} @ ${size}"
17 |
18 | png_output_dir="${EXPORT_DIR}/${size}x${size}/apps"
19 | if [[ ! -d "${png_output_dir}" ]]; then
20 | mkdir -p "${png_output_dir}"
21 | fi
22 |
23 | png_file="${png_output_dir}/${svg_name%.*}.png"
24 |
25 | echo "-> ${png_file}"
26 |
27 | inkscape --export-type="png" \
28 | --export-filename="${png_file}" \
29 | --export-area-page \
30 | --export-width="${size}" \
31 | --export-height="${size}" \
32 | "${svg_file}"
33 |
34 | optipng -o7 "${png_file}"
35 | done
36 | done
37 |
--------------------------------------------------------------------------------
/scripts/rebuild-translations.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -e
4 |
5 | SCRIPT_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
6 | cd "${SCRIPT_DIR}/.."
7 |
8 | # We must first perform a native build.
9 | BUILD_DIR="build-native"
10 | meson "${BUILD_DIR}" --wipe --prefix=/usr
11 | cd "${BUILD_DIR}"
12 | ninja
13 |
14 | # Now we can update the translations.
15 | ninja com.vysp3r.ProtonPlus-update-po
16 |
--------------------------------------------------------------------------------
/scripts/set-version.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | from pathlib import Path
4 | import re
5 | import sys
6 |
7 |
8 | SCRIPT_DIR = Path(__file__).parent.absolute()
9 |
10 |
11 | def die(msg: str) -> None:
12 | print(msg)
13 | exit(1)
14 |
15 |
16 | def file_rgx_replace(
17 | rgx: str, replacement: str, file: Path, max_count: int = 1, debug: bool = False
18 | ) -> None:
19 | print(f'Patching "{file.name}"...')
20 | text = file.read_text(encoding="utf-8")
21 | text = re.sub(rgx, replacement, text, max_count)
22 | if debug:
23 | print(text)
24 | else:
25 | file.write_text(text, encoding="utf-8")
26 |
27 |
28 | new_version: str | None = None
29 | if len(sys.argv) < 2:
30 | die("Usage: set-version.py \nExample: set-version.py 0.5.23")
31 |
32 | new_version = sys.argv[1]
33 | if re.search(r"^[0-9.\-]+$", new_version) is None:
34 | die(f'Invalid version specifier: "{new_version}"')
35 |
36 | file_rgx_replace( # Application version constant.
37 | r"(\bversion: ')[0-9.\-]+",
38 | rf"version: '{new_version}",
39 | SCRIPT_DIR / "../meson.build",
40 | )
41 |
42 | file_rgx_replace( # Flathub manifest.
43 | r"(\burl: .+?\/ProtonPlus\.git[\s]*\btag:) v[0-9.\-]+",
44 | rf"\1 v{new_version}",
45 | SCRIPT_DIR / "../com.vysp3r.ProtonPlus.yml",
46 | )
47 |
48 | print(
49 | "Remember to perform the following actions manually:\n"
50 | f'- Add the version number ("{new_version}") and release notes to "data/com.vysp3r.ProtonPlus.metainfo.xml.in".\n'
51 | f'- Then create and publish a new Git tag: "v{new_version}"'
52 | )
53 |
--------------------------------------------------------------------------------
/src/config.vapi:
--------------------------------------------------------------------------------
1 | [CCode (cprefix = "", lower_case_cprefix = "", cheader_filename = "config.h")]
2 | namespace ProtonPlus.Config {
3 | public const string APP_NAME;
4 | public const string APP_ID;
5 | public const string APP_VERSION;
6 | public const string LOCALE_DIR;
7 | public const string RESOURCE_BASE;
8 | }
--------------------------------------------------------------------------------
/src/main.vala:
--------------------------------------------------------------------------------
1 | namespace ProtonPlus {
2 | public static int main (string[] args) {
3 | if (!Thread.supported ()) {
4 | message ("Threads are not supported!");
5 | return -1;
6 | }
7 |
8 | Intl.bindtextdomain (Config.APP_ID, Config.LOCALE_DIR);
9 | Intl.bind_textdomain_codeset (Config.APP_ID, "UTF-8");
10 | Intl.textdomain (Config.APP_ID);
11 |
12 | var application = new Widgets.Application ();
13 | return application.run (args);
14 | }
15 | }
--------------------------------------------------------------------------------
/src/meson.build:
--------------------------------------------------------------------------------
1 | protonplus_sources = files(
2 | 'main.vala',
3 |
4 | 'widgets/application.vala',
5 | 'widgets/window.vala',
6 | 'widgets/info-box.vala',
7 | 'widgets/status-box.vala',
8 | 'widgets/sidebar.vala',
9 | 'widgets/sidebar-row.vala',
10 | 'widgets/release-row.vala',
11 | 'widgets/busy-dialog.vala',
12 | 'widgets/load-more-row.vala',
13 | 'widgets/launcher-box.vala',
14 | 'widgets/runner-group.vala',
15 | 'widgets/runner-row.vala',
16 | 'widgets/description-dialog.vala',
17 |
18 | 'widgets/release-rows/steamtinkerlaunch.vala',
19 | 'widgets/release-rows/basic.vala',
20 |
21 | 'widgets/busy-dialogs/install-dialog.vala',
22 | 'widgets/busy-dialogs/upgrade-dialog.vala',
23 | 'widgets/busy-dialogs/remove-dialog.vala',
24 |
25 | 'models/group.vala',
26 | 'models/launcher.vala',
27 | 'models/release.vala',
28 | 'models/runner.vala',
29 | 'models/parameters.vala',
30 |
31 | 'models/launchers/bottles.vala',
32 | 'models/launchers/hgl.vala',
33 | 'models/launchers/lutris.vala',
34 | 'models/launchers/steam.vala',
35 |
36 | 'models/runners/basic.vala',
37 | 'models/runners/github.vala',
38 | 'models/runners/github-action.vala',
39 | 'models/runners/gitlab.vala',
40 | 'models/runners/proton-ge.vala',
41 | 'models/runners/luxtorpeda.vala',
42 | 'models/runners/boxtron.vala',
43 | 'models/runners/roberta.vala',
44 | 'models/runners/northstar-proton.vala',
45 | 'models/runners/proton-ge-rstp.vala',
46 | 'models/runners/proton-tkg.vala',
47 | 'models/runners/proton-cachyos.vala',
48 | 'models/runners/proton-em.vala',
49 | 'models/runners/proton-sarek.vala',
50 | 'models/runners/proton-sarek-async.vala',
51 | 'models/runners/steamtinkerlaunch.vala',
52 | 'models/runners/kron4ek-wine-builds-staging-tkg.vala',
53 | 'models/runners/kron4ek-wine-builds-staging.vala',
54 | 'models/runners/kron4ek-wine-builds-vanilla.vala',
55 | 'models/runners/other.vala',
56 | 'models/runners/dxvk-async-sarek.vala',
57 | 'models/runners/dxvk-gpl-async-ph42on.vala',
58 | 'models/runners/dxvk-sarek.vala',
59 | 'models/runners/dxvk-doitsujin.vala',
60 | 'models/runners/vkd3d-lutris.vala',
61 | 'models/runners/vkd3d-proton.vala',
62 |
63 | 'models/releases/basic.vala',
64 | 'models/releases/github-action.vala',
65 | 'models/releases/upgrade.vala',
66 | 'models/releases/steamtinkerlaunch.vala',
67 |
68 | 'utils/filesystem.vala',
69 | 'utils/web.vala',
70 | 'utils/parser.vala',
71 | 'utils/system.vala',
72 | )
73 |
74 | protonplus_deps = [
75 | config_dep,
76 | dependency('gtk4'),
77 | dependency('glib-2.0'),
78 | dependency('libadwaita-1', version: '>= 1.5'),
79 | dependency('json-glib-1.0'),
80 | dependency('libsoup-3.0'),
81 | dependency('gee-0.8'),
82 | dependency('libarchive')
83 | ]
84 |
85 | executable(
86 | meson.project_name().split('.')[2].to_lower(),
87 | ui_gresource,
88 | css_gresource,
89 | icons_gresource,
90 | images_gresource,
91 | protonplus_sources,
92 | dependencies: protonplus_deps,
93 | include_directories: config_inc,
94 | install: true
95 | )
96 |
--------------------------------------------------------------------------------
/src/models/group.vala:
--------------------------------------------------------------------------------
1 | namespace ProtonPlus.Models {
2 | public class Group : Object {
3 | public string title { get; set; }
4 | public string description { get; set; }
5 | public string directory { get; set; }
6 | public Launcher launcher { get; set; }
7 |
8 | public List runners;
9 |
10 | public Group (string title, string description, string directory, Launcher launcher) {
11 | this.title = title;
12 | this.description = description;
13 | this.directory = directory;
14 | this.launcher = launcher;
15 |
16 | if (!FileUtils.test (launcher.directory + directory, FileTest.IS_DIR)) {
17 | Utils.Filesystem.create_directory.begin (launcher.directory + directory, (obj, res) => {
18 | Utils.Filesystem.create_directory.end (res);
19 | });
20 | }
21 | }
22 | }
23 | }
--------------------------------------------------------------------------------
/src/models/launcher.vala:
--------------------------------------------------------------------------------
1 | namespace ProtonPlus.Models {
2 | public class Launcher : Object {
3 | public string title;
4 | public string icon_path;
5 | public string directory;
6 | public bool installed;
7 |
8 | public Group[] groups;
9 |
10 | public InstallationTypes installation_type;
11 | public enum InstallationTypes {
12 | SYSTEM,
13 | FLATPAK,
14 | SNAP
15 | }
16 |
17 | public delegate bool callback (Release release);
18 | public signal bool install (Release release);
19 | public signal bool uninstall (Release release);
20 |
21 | public Launcher (string title, InstallationTypes installation_type, string icon_path, string[] directories) {
22 | this.title = title;
23 | this.installation_type = installation_type;
24 | this.icon_path = icon_path;
25 | this.directory = "";
26 |
27 | foreach (var directory in directories) {
28 | var current_path = Environment.get_home_dir () + directory;
29 | if (FileUtils.test (current_path, FileTest.IS_DIR)) {
30 | if (title == "Steam") {
31 | if (FileUtils.test (current_path + "/steamclient.dll", FileTest.IS_REGULAR) && FileUtils.test (current_path + "/steamclient64.dll", FileTest.IS_REGULAR)) {
32 | this.directory = current_path;
33 | break;
34 | }
35 | } else {
36 | this.directory = current_path;
37 | break;
38 | }
39 | }
40 | }
41 |
42 | installed = directory.length > 0;
43 | }
44 |
45 | public string get_installation_type_title () {
46 | switch (installation_type) {
47 | case InstallationTypes.SYSTEM:
48 | return "System";
49 | case InstallationTypes.FLATPAK:
50 | return "Flatpak";
51 | case InstallationTypes.SNAP:
52 | return "Snap";
53 | default:
54 | return "Invalid type";
55 | }
56 | }
57 |
58 | public static List get_all () {
59 | var launchers = new List ();
60 |
61 | launchers.append (new Launchers.Steam (InstallationTypes.SYSTEM));
62 | launchers.append (new Launchers.Steam (InstallationTypes.FLATPAK));
63 | launchers.append (new Launchers.Steam (InstallationTypes.SNAP));
64 |
65 | launchers.append (new Launchers.Lutris (InstallationTypes.SYSTEM));
66 | launchers.append (new Launchers.Lutris (InstallationTypes.FLATPAK));
67 |
68 | launchers.append (new Launchers.Bottles (InstallationTypes.SYSTEM));
69 | launchers.append (new Launchers.Bottles (InstallationTypes.FLATPAK));
70 |
71 | launchers.append (new Launchers.HeroicGamesLauncher (InstallationTypes.SYSTEM));
72 | launchers.append (new Launchers.HeroicGamesLauncher (InstallationTypes.FLATPAK));
73 |
74 | launchers.foreach ((launcher) => {
75 | if (!launcher.installed)launchers.remove (launcher);
76 | });
77 |
78 | return (owned) launchers;
79 | }
80 | }
81 | }
--------------------------------------------------------------------------------
/src/models/launchers/bottles.vala:
--------------------------------------------------------------------------------
1 | namespace ProtonPlus.Models.Launchers {
2 | public class Bottles : Launcher {
3 | public Bottles (Launcher.InstallationTypes installation_type) {
4 | string[] directories = null;
5 |
6 | switch (installation_type) {
7 | case Launcher.InstallationTypes.SYSTEM:
8 | directories = new string[] { "/.local/share/bottles" };
9 | break;
10 | case Launcher.InstallationTypes.FLATPAK:
11 | directories = new string[] { "/.var/app/com.usebottles.bottles/data/bottles" };
12 | break;
13 | case Launcher.InstallationTypes.SNAP:
14 | break;
15 | }
16 |
17 | base ("Bottles", installation_type, Config.RESOURCE_BASE + "/bottles.png", directories);
18 |
19 | if (installed) {
20 | groups = get_groups ();
21 | install.connect ((release) => true);
22 | uninstall.connect ((release) => true);
23 | }
24 | }
25 |
26 | Group[] get_groups () {
27 | var groups = new Group[2];
28 |
29 | groups[0] = new Group (_("Runners"), _("Compatibility tools for running Windows software on Linux."), "/runners", this);
30 | groups[0].runners = get_runners (groups[0]);
31 |
32 | groups[1] = new Group ("DXVK", _("Vulkan-based implementation of Direct3D 8, 9, 10 and 11 for Linux/Wine."), "/dxvk", this);
33 | groups[1].runners = get_dxvk_runners (groups[1]);
34 |
35 | return groups;
36 | }
37 |
38 | List get_runners (Group group) {
39 | var runners = new List ();
40 |
41 | runners.append (new Runners.Proton_GE (group));
42 | runners.append (new Runners.Proton_CachyOS (group));
43 | runners.append (new Runners.Proton_EM (group));
44 | runners.append (new Runners.Other (group));
45 |
46 | return runners;
47 | }
48 |
49 | List get_dxvk_runners (Group group) {
50 | var runners = new List ();
51 |
52 | runners.append (new Runners.DXVK_doitsujin (group));
53 |
54 | return runners;
55 | }
56 | }
57 | }
--------------------------------------------------------------------------------
/src/models/launchers/hgl.vala:
--------------------------------------------------------------------------------
1 | namespace ProtonPlus.Models.Launchers {
2 | public class HeroicGamesLauncher : Launcher {
3 | public HeroicGamesLauncher (Launcher.InstallationTypes installation_type) {
4 | string[] directories = null;
5 |
6 | switch (installation_type) {
7 | case Launcher.InstallationTypes.SYSTEM:
8 | directories = new string[] { "/.config/heroic" };
9 | break;
10 | case Launcher.InstallationTypes.FLATPAK:
11 | directories = new string[] { "/.var/app/com.heroicgameslauncher.hgl/config/heroic" };
12 | break;
13 | case Launcher.InstallationTypes.SNAP:
14 | break;
15 | }
16 |
17 | base ("Heroic Games Launcher", installation_type, Config.RESOURCE_BASE + "/hgl.png", directories);
18 |
19 | if (installed) {
20 | groups = get_groups ();
21 | install.connect ((release) => install_script (release));
22 | uninstall.connect ((release) => uninstall_script (release));
23 | }
24 | }
25 |
26 | Group[] get_groups () {
27 | var groups = new Group[2];
28 |
29 | groups[0] = new Group ("Proton", _("Compatibility tools by Valve for running Windows software on Linux."), "/tools/proton", this);
30 | groups[0].runners = get_proton_runners (groups[0]);
31 |
32 | groups[1] = new Group ("Wine", _("Compatibility tools for running Windows software on Linux."), "/tools/wine", this);
33 | groups[1].runners = get_wine_runners (groups[1]);
34 |
35 | return groups;
36 | }
37 |
38 | List get_wine_runners (Group group) {
39 | var runners = new List ();
40 |
41 | runners.append (new Runners.Wine_Vanilla_Kron4ek (group));
42 | runners.append (new Runners.Wine_Staging_Kron4ek (group));
43 | runners.append (new Runners.Wine_Staging_Tkg_Kron4ek (group));
44 |
45 | return runners;
46 | }
47 |
48 | List get_proton_runners (Group group) {
49 | var runners = new List ();
50 |
51 | runners.append (new Runners.Proton_GE (group));
52 | runners.append (new Runners.Proton_CachyOS (group));
53 | runners.append (new Runners.Proton_EM (group));
54 | runners.append (new Runners.Proton_Tkg (group));
55 |
56 | return runners;
57 | }
58 |
59 | bool install_script (Release release) {
60 | try {
61 | string path = "/.config";
62 | if (release.runner.group.launcher.installation_type == Launcher.InstallationTypes.FLATPAK)path = "/.var/app/com.heroicgameslauncher.hgl/config";
63 | path = Environment.get_home_dir () + path + "/heroic/store/wine-downloader-info.json";
64 |
65 | Json.Node root_node = Json.from_string (Utils.Filesystem.get_file_content (path));
66 | Json.Object root_object = root_node.get_object ();
67 |
68 | var wine_release_array = root_object.get_array_member ("wine-releases");
69 | if (wine_release_array == null)
70 | return false;
71 |
72 | bool found = false;
73 |
74 | var runner = release.runner as Runners.Basic;
75 |
76 | var installDirBase = release.runner.group.launcher.directory + release.runner.group.directory + "/";
77 |
78 | for (var i = 0; i < wine_release_array.get_length (); i++) {
79 | var obj = wine_release_array.get_object_element (i);
80 |
81 | if (obj.get_string_member ("version").contains (runner.get_directory_name (release.title))) {
82 | obj.set_boolean_member ("isInstalled", true);
83 | obj.set_boolean_member ("hasUpdate", false);
84 | obj.set_string_member ("installDir", installDirBase + obj.get_string_member ("version"));
85 |
86 | obj.set_int_member ("disksize", (int64) Utils.Filesystem.get_directory_size (obj.get_string_member ("installDir")));
87 |
88 | found = true;
89 | }
90 | }
91 |
92 | if (!found) {
93 | var obj = new Json.Object ();
94 |
95 | obj.set_string_member ("version", runner.get_directory_name (release.title));
96 | obj.set_string_member ("type", release.runner.title);
97 | obj.set_string_member ("date", "");
98 | obj.set_string_member ("checksum", "");
99 | obj.set_string_member ("download", "");
100 | obj.set_int_member ("downsize", 0);
101 |
102 | obj.set_boolean_member ("isInstalled", true);
103 | obj.set_boolean_member ("hasUpdate", false);
104 | obj.set_string_member ("installDir", installDirBase + obj.get_string_member ("version"));
105 |
106 | obj.set_int_member ("disksize", (int64) Utils.Filesystem.get_directory_size (obj.get_string_member ("installDir")));
107 |
108 | wine_release_array.add_object_element (obj);
109 | }
110 |
111 | Utils.Filesystem.modify_file (path, Json.to_string (root_node, true));
112 |
113 | return true;
114 | } catch (Error e) {
115 | message (e.message);
116 |
117 | return false;
118 | }
119 | }
120 |
121 | bool uninstall_script (Release release) {
122 | try {
123 | string path = "/.config";
124 | if (release.runner.group.launcher.installation_type == Launcher.InstallationTypes.FLATPAK)path = "/.var/app/com.heroicgameslauncher.hgl/config";
125 | path = Environment.get_home_dir () + path + "/heroic/store/wine-downloader-info.json";
126 |
127 | Json.Node root_node = Json.from_string (Utils.Filesystem.get_file_content (path));
128 | Json.Object root_object = root_node.get_object ();
129 |
130 | var wine_release_array = root_object.get_array_member ("wine-releases");
131 | if (wine_release_array == null)
132 | return false;
133 |
134 | for (var i = 0; i < wine_release_array.get_length (); i++) {
135 | var obj = wine_release_array.get_object_element (i);
136 |
137 | var runner = release.runner as Runners.Basic;
138 |
139 | if (obj.get_string_member ("version").contains (runner.get_directory_name (release.title))) {
140 | obj.remove_member ("isInstalled");
141 | obj.remove_member ("hasUpdate");
142 | obj.remove_member ("installDir");
143 | obj.set_int_member ("disksize", 0);
144 | }
145 | }
146 |
147 | Utils.Filesystem.modify_file (path, Json.to_string (root_node, true));
148 |
149 | return true;
150 | } catch (Error e) {
151 | message (e.message);
152 |
153 | return false;
154 | }
155 | }
156 | }
157 | }
--------------------------------------------------------------------------------
/src/models/launchers/lutris.vala:
--------------------------------------------------------------------------------
1 | namespace ProtonPlus.Models.Launchers {
2 | public class Lutris : Launcher {
3 | public Lutris (Launcher.InstallationTypes installation_type) {
4 | string[] directories = null;
5 |
6 | switch (installation_type) {
7 | case Launcher.InstallationTypes.SYSTEM:
8 | directories = new string[] { "/.local/share/lutris" };
9 | break;
10 | case Launcher.InstallationTypes.FLATPAK:
11 | directories = new string[] { "/.var/app/net.lutris.Lutris/data/lutris" };
12 | break;
13 | case Launcher.InstallationTypes.SNAP:
14 | break;
15 | }
16 |
17 | base ("Lutris", installation_type, Config.RESOURCE_BASE + "/lutris.png", directories);
18 |
19 | if (installed) {
20 | groups = get_groups ();
21 | install.connect ((release) => true);
22 | uninstall.connect ((release) => true);
23 |
24 | Utils.Filesystem.create_directory.begin (directory + "/runners/proton", (obj, res) => {
25 | Utils.Filesystem.create_directory.end (res);
26 | });
27 | }
28 | }
29 |
30 | Group[] get_groups () {
31 | var groups = new Group[4];
32 |
33 | groups[0] = new Group ("Proton", _("Compatibility tools by Valve for running Windows software on Linux."), "/runners/proton", this);
34 | groups[0].runners = get_proton_runners (groups[0]);
35 |
36 | groups[1] = new Group ("Wine", _("Compatibility tools for running Windows software on Linux."), "/runners/wine", this);
37 | groups[1].runners = get_wine_runners (groups[1]);
38 |
39 | groups[2] = new Group ("DXVK", _("Vulkan-based implementation of Direct3D 8, 9, 10 and 11 for Linux/Wine."), "/runtime/dxvk", this);
40 | groups[2].runners = get_dxvk_runners (groups[2]);
41 |
42 | groups[3] = new Group ("VKD3D", _("Variant of Wine's VKD3D which aims to implement the full Direct3D 12 API on top of Vulkan."), "/runtime/vkd3d", this);
43 | groups[3].runners = get_vkd3d_runners (groups[3]);
44 |
45 | return groups;
46 | }
47 |
48 | List get_proton_runners (Group group) {
49 | var runners = new List ();
50 |
51 | runners.append (new Runners.Proton_GE (group));
52 | runners.append (new Runners.Proton_CachyOS (group));
53 | runners.append (new Runners.Proton_EM (group));
54 | runners.append (new Runners.Proton_Sarek (group));
55 | runners.append (new Runners.Proton_Sarek_Async (group));
56 | runners.append (new Runners.Proton_Tkg (group));
57 |
58 | return runners;
59 | }
60 |
61 | List get_wine_runners (Group group) {
62 | var runners = new List ();
63 |
64 | runners.append (new Runners.Wine_Vanilla_Kron4ek (group));
65 | runners.append (new Runners.Wine_Staging_Kron4ek (group));
66 | runners.append (new Runners.Wine_Staging_Tkg_Kron4ek (group));
67 |
68 | return runners;
69 | }
70 |
71 | List get_dxvk_runners (Group group) {
72 | var runners = new List ();
73 |
74 | runners.append (new Runners.DXVK_doitsujin (group));
75 | runners.append (new Runners.DXVK_GPL_Async_Ph42oN (group));
76 | runners.append (new Runners.DXVK_Sarek (group));
77 | runners.append (new Runners.DXVK_Async_Sarek (group));
78 |
79 | return runners;
80 | }
81 |
82 | List get_vkd3d_runners (Group group) {
83 | var runners = new List ();
84 |
85 | runners.append (new Runners.VKD3D_Lutris (group));
86 | runners.append (new Runners.VKD3D_Proton (group));
87 |
88 | return runners;
89 | }
90 | }
91 | }
--------------------------------------------------------------------------------
/src/models/launchers/steam.vala:
--------------------------------------------------------------------------------
1 | namespace ProtonPlus.Models.Launchers {
2 | public class Steam : Launcher {
3 | public Steam (Launcher.InstallationTypes installation_type) {
4 | string[] directories = null;
5 |
6 | switch (installation_type) {
7 | case Launcher.InstallationTypes.SYSTEM:
8 | directories = new string[] { "/.local/share/Steam",
9 | "/.steam/root",
10 | "/.steam/steam",
11 | "/.steam/debian-installation" };
12 | break;
13 | case Launcher.InstallationTypes.FLATPAK:
14 | directories = new string[] { "/.var/app/com.valvesoftware.Steam/data/Steam" };
15 | break;
16 | case Launcher.InstallationTypes.SNAP:
17 | directories = new string[] { "/snap/steam/common/.steam/root" };
18 | break;
19 | }
20 |
21 | base ("Steam", installation_type, Config.RESOURCE_BASE + "/steam.png", directories);
22 |
23 | if (installed) {
24 | groups = get_groups ();
25 | install.connect ((release) => true);
26 | uninstall.connect ((release) => true);
27 | }
28 | }
29 |
30 | Group[] get_groups () {
31 | var groups = new Group[1];
32 |
33 | groups[0] = new Group (_("Runners"), "", "/compatibilitytools.d", this);
34 | groups[0].runners = get_runners (groups[0]);
35 |
36 | return groups;
37 | }
38 |
39 | public static List get_runners (Group group) {
40 | var runners = new List ();
41 |
42 | runners.append (new Runners.Proton_GE (group));
43 | runners.append (new Runners.Proton_CachyOS (group));
44 | runners.append (new Runners.Proton_EM (group));
45 | runners.append (new Runners.Proton_Sarek (group));
46 | runners.append (new Runners.Proton_Sarek_Async (group));
47 | runners.append (new Runners.Proton_GE_RSTP (group));
48 | runners.append (new Runners.Proton_Tkg (group));
49 | runners.append (new Runners.Northstar_Proton (group));
50 | runners.append (new Runners.Luxtorpeda (group));
51 | runners.append (new Runners.Boxtron (group));
52 | runners.append (new Runners.Roberta (group));
53 | runners.append (new Runners.SteamTinkerLaunch (group));
54 |
55 | return runners;
56 | }
57 | }
58 | }
--------------------------------------------------------------------------------
/src/models/parameters.vala:
--------------------------------------------------------------------------------
1 | namespace ProtonPlus.Models {
2 | public class Parameters : Object {
3 |
4 | }
5 | }
--------------------------------------------------------------------------------
/src/models/release.vala:
--------------------------------------------------------------------------------
1 | namespace ProtonPlus.Models {
2 | public abstract class Release: Object {
3 | public Runner runner { get; set; }
4 | public string title { get; set; }
5 | public string displayed_title { get; set; }
6 | public string description { get; set; }
7 | public string release_date { get; set; }
8 | public string download_url { get; set; }
9 | public string page_url { get; set; }
10 | public bool canceled { get; set; }
11 | public string progress { get; set; }
12 | public signal void send_message (string message);
13 |
14 | public State state { get; set; }
15 | public enum State {
16 | NOT_INSTALLED,
17 | UPDATE_AVAILABLE,
18 | UP_TO_DATE,
19 | BUSY_INSTALLING,
20 | BUSY_REMOVING,
21 | BUSY_UPGRADING,
22 | }
23 |
24 | construct {
25 | notify["state"].connect (state_changed);
26 | }
27 |
28 | void state_changed () {
29 | switch (state) {
30 | case State.BUSY_INSTALLING:
31 | send_message (_("The installation of %s has begun.").printf (title));
32 | break;
33 | case State.BUSY_REMOVING:
34 | send_message (_("The removal of %s has begun.").printf (title));
35 | break;
36 | case State.BUSY_UPGRADING:
37 | send_message (_("The upgrade of %s has begun.").printf (title));
38 | break;
39 | default:
40 | break;
41 | }
42 | }
43 |
44 | public async bool install () {
45 | var busy_upgrading = state == State.BUSY_UPGRADING;
46 |
47 | if (!busy_upgrading)
48 | state = State.BUSY_INSTALLING;
49 |
50 | // Attempt the installation.
51 | var install_success = yield _start_install ();
52 |
53 | if (!install_success) {
54 | yield remove (new Models.Parameters ()); // Refreshes install state too.
55 |
56 | if (!busy_upgrading)
57 | send_message (_("An unexpected error occurred while installing %s.").printf (title));
58 | } else if (!busy_upgrading)
59 | send_message (_("The installation of %s is complete.").printf (title));
60 |
61 | if (!busy_upgrading)
62 | refresh_state (); // Force UI state refresh.
63 |
64 | return install_success;
65 | }
66 |
67 | protected abstract async bool _start_install ();
68 |
69 | public async bool remove (R parameters) {
70 | var busy_upgrading_or_instaling = state == State.BUSY_UPGRADING || state == State.BUSY_INSTALLING;
71 |
72 | if (!busy_upgrading_or_instaling)
73 | state = State.BUSY_REMOVING;
74 |
75 | // Attempt the removal.
76 | var remove_success = yield _start_remove (parameters);
77 |
78 | if (!busy_upgrading_or_instaling) {
79 | send_message ((remove_success ? _("The removal of %s is complete.") : _("An unexpected error occurred while removing %s.")).printf (title));
80 | refresh_state (); // Force UI state refresh.
81 | }
82 |
83 | return remove_success;
84 | }
85 |
86 | protected abstract async bool _start_remove (R parameters);
87 |
88 | protected abstract void refresh_state ();
89 | }
90 | }
--------------------------------------------------------------------------------
/src/models/releases/basic.vala:
--------------------------------------------------------------------------------
1 | namespace ProtonPlus.Models.Releases {
2 | public class Basic : Release {
3 | public string install_location { get; set; }
4 | public int64 download_size { get; set; }
5 |
6 | public Basic.simple (Runners.Basic runner, string title, string install_location) {
7 | this.runner = runner;
8 | this.title = title;
9 | this.install_location = install_location;
10 | }
11 |
12 | public Basic.github (Runners.Basic runner, string title, string description, string release_date, int64 download_size, string download_url, string page_url) {
13 | this.description = description;
14 | this.download_size = download_size;
15 |
16 | shared (runner, title, release_date, download_url, page_url);
17 | }
18 |
19 | public Basic.gitlab (Runners.Basic runner, string title, string description, string release_date, string download_url, string page_url) {
20 | this.description = description;
21 |
22 | shared (runner, title, release_date, download_url, page_url);
23 | }
24 |
25 | internal void shared (Runners.Basic runner, string title, string release_date, string download_url, string page_url) {
26 | this.runner = runner;
27 | this.title = title;
28 | this.displayed_title = title;
29 | this.description = description;
30 | this.release_date = release_date;
31 | this.download_url = download_url;
32 | this.page_url = page_url;
33 |
34 | install_location = runner.group.launcher.directory + runner.group.directory + "/" + runner.get_directory_name (title);
35 |
36 | refresh_state ();
37 | }
38 |
39 | protected override void refresh_state () {
40 | canceled = false;
41 |
42 | state = FileUtils.test (install_location, FileTest.IS_DIR) ? State.UP_TO_DATE : State.NOT_INSTALLED;
43 | }
44 |
45 | protected override async bool _start_install () {
46 | send_message (_("Downloading..."));
47 |
48 | string path = runner.group.launcher.directory + runner.group.directory + "/" + title + ".tar.gz";
49 |
50 | var download_valid = yield Utils.Web.Download (download_url, path, () => canceled, (is_percent, progress) => this.progress = is_percent? @"$progress%" : Utils.Filesystem.convert_bytes_to_string (progress));
51 |
52 | if (!download_valid)
53 | return false;
54 |
55 | send_message (_("Extracting..."));
56 |
57 | string directory = runner.group.launcher.directory + "/" + runner.group.directory + "/";
58 |
59 | string source_path = yield Utils.Filesystem.extract (directory, title, ".tar.gz", () => canceled);
60 |
61 | if (source_path == "")
62 | return false;
63 |
64 | send_message (_("Renaming..."));
65 |
66 | var runner = this.runner as Runners.Basic;
67 |
68 | var renaming_valid = yield Utils.Filesystem.rename (source_path, directory + runner.get_directory_name (title));
69 |
70 | if (!renaming_valid)
71 | return false;
72 |
73 | send_message (_("Running post installation script..."));
74 |
75 | var install_script_success = runner.group.launcher.install (this);
76 |
77 | if (!install_script_success)
78 | return false;
79 |
80 | return true;
81 | }
82 |
83 | protected override async bool _start_remove (Parameters parameters) {
84 | send_message (_("Deleting..."));
85 |
86 | var deleted = yield Utils.Filesystem.delete_directory (install_location);
87 |
88 | if (!deleted)
89 | return false;
90 |
91 | send_message (_("Running post removal script..."));
92 |
93 | var uninstall_script_success = runner.group.launcher.uninstall (this);
94 |
95 | if (!uninstall_script_success)
96 | return false;
97 |
98 | return true;
99 | }
100 | }
101 | }
--------------------------------------------------------------------------------
/src/models/releases/github-action.vala:
--------------------------------------------------------------------------------
1 | namespace ProtonPlus.Models.Releases {
2 | public class GitHubAction : Basic {
3 | public string artifacts_url { get; set; }
4 |
5 | public GitHubAction (Runners.Basic runner, string title, string release_date, string download_url, string page_url, string artifacts_url) {
6 | this.artifacts_url = artifacts_url;
7 |
8 | shared (runner, title, release_date, download_url, page_url);
9 |
10 | displayed_title = @"$title ($release_date)";
11 | }
12 |
13 | protected override async bool _start_install () {
14 | send_message (_("Downloading..."));
15 |
16 | string path = runner.group.launcher.directory + runner.group.directory + "/" + title + ".tar.gz";
17 |
18 | var download_valid = yield Utils.Web.Download (download_url, path, () => canceled, (is_percent, progress) => this.progress = is_percent? @"$progress%" : Utils.Filesystem.convert_bytes_to_string (progress));
19 |
20 | if (!download_valid)
21 | return false;
22 |
23 | send_message (_("Extracting..."));
24 |
25 | string directory = runner.group.launcher.directory + "/" + runner.group.directory + "/";
26 |
27 | string source_path = yield Utils.Filesystem.extract (directory, title, ".tar.gz", () => canceled);
28 |
29 | if (source_path == "")
30 | return false;
31 |
32 | source_path = yield Utils.Filesystem.extract (directory, source_path.substring (0, source_path.length - 4).replace (directory, ""), ".tar", () => canceled);
33 |
34 | if (source_path == "")
35 | return false;
36 |
37 | send_message (_("Renaming..."));
38 |
39 | var runner = this.runner as Runners.Basic;
40 |
41 | var renaming_valid = yield Utils.Filesystem.rename (source_path, directory + runner.get_directory_name (title));
42 |
43 | if (!renaming_valid)
44 | return false;
45 |
46 | send_message (_("Running post installation script..."));
47 |
48 | var install_script_success = runner.group.launcher.install (this);
49 |
50 | if (!install_script_success)
51 | return false;
52 |
53 | return true;
54 | }
55 | }
56 | }
--------------------------------------------------------------------------------
/src/models/releases/upgrade.vala:
--------------------------------------------------------------------------------
1 | namespace ProtonPlus.Models.Releases {
2 | public abstract class Upgrade: Release {
3 | public async bool upgrade () {
4 | state = State.BUSY_UPGRADING;
5 |
6 | var upgrade_success = yield _start_upgrade ();
7 |
8 | send_message ((upgrade_success ? _("The upgrade of %s is complete.") : _("An unexpected error occurred while upgrading %s.")).printf (title));
9 |
10 | refresh_state ();
11 |
12 | return upgrade_success;
13 | }
14 |
15 | protected abstract async bool _start_upgrade ();
16 | }
17 | }
--------------------------------------------------------------------------------
/src/models/runner.vala:
--------------------------------------------------------------------------------
1 | namespace ProtonPlus.Models {
2 | public abstract class Runner : Object {
3 | public string title { get; set; }
4 | public string description { get; set; }
5 | public Group group { get; set; }
6 | public bool has_more { get; set; } // TODO Find a better name
7 | public List releases;
8 |
9 | public abstract async List load();
10 | }
11 | }
--------------------------------------------------------------------------------
/src/models/runners/basic.vala:
--------------------------------------------------------------------------------
1 | namespace ProtonPlus.Models.Runners {
2 | public abstract class Basic : Runner {
3 | internal int asset_position { get; set; } // TODO Describe this
4 | internal string endpoint { get; set; } // TODO Describe this
5 | internal int page { get; set; } // TODO Describe this
6 |
7 | construct {
8 | page = 1;
9 | }
10 |
11 | public abstract string get_directory_name (string release_name);
12 | }
13 | }
--------------------------------------------------------------------------------
/src/models/runners/boxtron.vala:
--------------------------------------------------------------------------------
1 | namespace ProtonPlus.Models.Runners {
2 | public class Boxtron : GitHub {
3 | public Boxtron(Group group) {
4 | Object(group: group,
5 | title: "Boxtron",
6 | description: _("Steam compatibility tool for running DOS games using DOSBox for Linux."),
7 | endpoint: "https://api.github.com/repos/dreamer/boxtron/releases",
8 | asset_position: 0);
9 | }
10 |
11 | public override string get_directory_name(string release_name) {
12 | return @"$title $release_name";
13 | }
14 | }
15 | }
--------------------------------------------------------------------------------
/src/models/runners/dxvk-async-sarek.vala:
--------------------------------------------------------------------------------
1 | namespace ProtonPlus.Models.Runners {
2 | public class DXVK_Async_Sarek : GitHub {
3 | public DXVK_Async_Sarek (Group group) {
4 | Object (group: group,
5 | title: "DXVK Async (Sarek)",
6 | description: _("DXVK Builds that work with pre-Vulkan 1.3 versions"),
7 | endpoint: "https://api.github.com/repos/pythonlover02/DXVK-Sarek/releases",
8 | asset_position: 0);
9 | }
10 |
11 | public override string get_directory_name (string release_name) {
12 | return release_name + "-async";
13 | }
14 | }
15 | }
--------------------------------------------------------------------------------
/src/models/runners/dxvk-doitsujin.vala:
--------------------------------------------------------------------------------
1 | namespace ProtonPlus.Models.Runners {
2 | public class DXVK_doitsujin : GitHub {
3 | public DXVK_doitsujin (Group group) {
4 | Object (group: group,
5 | title: "DXVK (doitsujin)",
6 | description: "",
7 | endpoint: "https://api.github.com/repos/doitsujin/dxvk/releases",
8 | asset_position: 0);
9 | }
10 |
11 | public override string get_directory_name (string release_name) {
12 | return release_name.replace ("v", "dxvk-");
13 | }
14 | }
15 | }
--------------------------------------------------------------------------------
/src/models/runners/dxvk-gpl-async-ph42on.vala:
--------------------------------------------------------------------------------
1 | namespace ProtonPlus.Models.Runners {
2 | public class DXVK_GPL_Async_Ph42oN : GitLab {
3 | public DXVK_GPL_Async_Ph42oN (Group group) {
4 | Object (group: group,
5 | title: "DXVK GPL+Async (Ph42oN)",
6 | description: "",
7 | endpoint: "https://gitlab.com/api/v4/projects/Ph42oN%2Fdxvk-gplasync/releases",
8 | asset_position: 0);
9 | }
10 |
11 | public override string get_directory_name (string release_name) {
12 | return @"dxvk-gplasync-" + release_name;
13 | }
14 | }
15 | }
--------------------------------------------------------------------------------
/src/models/runners/dxvk-sarek.vala:
--------------------------------------------------------------------------------
1 | namespace ProtonPlus.Models.Runners {
2 | public class DXVK_Sarek : GitHub {
3 | public DXVK_Sarek (Group group) {
4 | Object (group: group,
5 | title: "DXVK (Sarek)",
6 | description: _("DXVK Builds that work with pre-Vulkan 1.3 versions"),
7 | endpoint: "https://api.github.com/repos/pythonlover02/DXVK-Sarek/releases",
8 | asset_position: 1);
9 | }
10 |
11 | public override string get_directory_name (string release_name) {
12 | return release_name;
13 | }
14 | }
15 | }
--------------------------------------------------------------------------------
/src/models/runners/github-action.vala:
--------------------------------------------------------------------------------
1 | namespace ProtonPlus.Models.Runners {
2 | public abstract class GitHubAction : Basic {
3 | internal string url_template { get; set; }
4 |
5 | public override async List load () {
6 | var temp_releases = new List ();
7 |
8 | var json = yield Utils.Web.GET (endpoint + "?per_page=25&page=" + page ++.to_string (), false);
9 |
10 | if (json == null || json.contains ("https://docs.github.com/rest/overview/resources-in-the-rest-api#rate-limiting"))
11 | return temp_releases;
12 |
13 | var root_node = Utils.Parser.get_node_from_json (json);
14 |
15 | var root_object = root_node.get_object ();
16 |
17 | if (!root_object.has_member ("workflow_runs") || root_object.get_member ("workflow_runs").get_node_type () != Json.NodeType.ARRAY)
18 | return temp_releases;
19 |
20 | var runs_array = root_object.get_array_member ("workflow_runs");
21 | if (runs_array == null)
22 | return temp_releases;
23 |
24 | for (var i = 0; i < runs_array.get_length (); i++) {
25 | var object = runs_array.get_object_element (i);
26 |
27 | string title = object.get_int_member ("run_number").to_string ();
28 | string page_url = object.get_string_member ("html_url");
29 | string release_date = object.get_string_member ("created_at").split ("T")[0];
30 | string download_url = url_template.replace ("{id}", object.get_int_member ("id").to_string ());
31 | string artifacts_url = object.get_string_member ("artifacts_url");
32 |
33 | if (object.get_string_member_with_default ("status", "") == "completed" && object.get_string_member_with_default ("conclusion", "") == "success") {
34 | var release = new Releases.GitHubAction (this, title, release_date, download_url, page_url, artifacts_url);
35 |
36 | releases.append (release);
37 | temp_releases.append (release);
38 | }
39 | }
40 |
41 | return temp_releases;
42 | }
43 | }
44 | }
--------------------------------------------------------------------------------
/src/models/runners/github.vala:
--------------------------------------------------------------------------------
1 | namespace ProtonPlus.Models.Runners {
2 | public abstract class GitHub : Basic {
3 | internal bool use_name_instead_of_tag_name { get; set; } // TODO Describe this
4 | internal string[] request_asset_exclude { get; set; } // TODO Describe this
5 |
6 | public override async List load () {
7 | var temp_releases = new List ();
8 |
9 | var json = yield Utils.Web.GET (endpoint + "?per_page=25&page=" + page ++.to_string (), false);
10 |
11 | if (json == null || json.contains ("https://docs.github.com/rest/overview/resources-in-the-rest-api#rate-limiting"))
12 | return temp_releases;
13 |
14 | var root_node = Utils.Parser.get_node_from_json (json);
15 |
16 | if (root_node == null)
17 | return temp_releases;
18 |
19 | if (root_node.get_node_type () != Json.NodeType.ARRAY)
20 | return temp_releases;
21 |
22 | var root_array = root_node.get_array ();
23 | if (root_array == null)
24 | return temp_releases;
25 |
26 | for (var i = 0; i < root_array.get_length (); i++) {
27 | var object = root_array.get_object_element (i);
28 |
29 | var asset_array = object.get_array_member ("assets");
30 | if (asset_array == null)
31 | continue;
32 |
33 | string title = use_name_instead_of_tag_name ? object.get_string_member ("name") : object.get_string_member ("tag_name");
34 | string description = object.get_string_member ("body").strip ();
35 | string page_url = object.get_string_member ("html_url");
36 | string release_date = object.get_string_member ("created_at").split ("T")[0];
37 |
38 | if (request_asset_exclude != null) {
39 | var excluded = false;
40 |
41 | foreach (var excluded_asset in request_asset_exclude) {
42 | if (title.contains (excluded_asset)) {
43 | excluded = true;
44 | break;
45 | }
46 | }
47 |
48 | if (excluded)
49 | continue;
50 | }
51 |
52 | if (asset_array.get_length () - 1 >= asset_position) {
53 | var asset_object = asset_array.get_object_element (asset_position);
54 |
55 | string download_url = asset_object.get_string_member ("browser_download_url");
56 | int64 download_size = asset_object.get_int_member ("size");
57 |
58 | var release = new Releases.Basic.github (this, title, description, release_date, download_size, download_url, page_url);
59 |
60 | releases.append (release);
61 | temp_releases.append (release);
62 | }
63 | }
64 |
65 | has_more = temp_releases.length () == 25;
66 |
67 | return temp_releases;
68 | }
69 | }
70 | }
--------------------------------------------------------------------------------
/src/models/runners/gitlab.vala:
--------------------------------------------------------------------------------
1 | namespace ProtonPlus.Models.Runners {
2 | public abstract class GitLab : Basic {
3 | internal bool use_name_instead_of_tag_name { get; set; } // TODO Describe this
4 | internal string[] request_asset_exclude { get; set; } // TODO Describe this
5 |
6 | public override async List load () {
7 | var temp_releases = new List ();
8 |
9 | var json = yield Utils.Web.GET (endpoint + "?per_page=25&page=" + page ++.to_string (), false);
10 |
11 | if (json == null)
12 | return temp_releases;
13 |
14 | var root_node = Utils.Parser.get_node_from_json (json);
15 |
16 | if (root_node == null || root_node.get_node_type () != Json.NodeType.ARRAY)
17 | return temp_releases;
18 |
19 | var root_array = root_node.get_array ();
20 | if (root_array == null)
21 | return temp_releases;
22 |
23 | for (var i = 0; i < root_array.get_length (); i++) {
24 | var object = root_array.get_object_element (i);
25 |
26 | string title = use_name_instead_of_tag_name ? object.get_string_member ("name") : object.get_string_member ("tag_name");
27 | string description = object.get_string_member ("description").strip ();;
28 | string release_date = object.get_string_member ("created_at").split ("T")[0];
29 |
30 | if (request_asset_exclude != null) {
31 | var excluded = false;
32 |
33 | foreach (var excluded_asset in request_asset_exclude) {
34 | if (title.contains (excluded_asset)) {
35 | excluded = true;
36 | break;
37 | }
38 | }
39 |
40 | if (excluded)
41 | continue;
42 | }
43 |
44 | var page_url_object = object.get_object_member ("_links");
45 | if (page_url_object == null)
46 | continue;
47 |
48 | string page_url = page_url_object.get_string_member ("self");
49 |
50 | var assets_object = object.get_object_member ("assets");
51 | if (assets_object == null)
52 | continue;
53 |
54 | var link_array = assets_object.get_array_member ("links");
55 | if (link_array == null)
56 | continue;
57 |
58 | if (link_array.get_length () - 1 >= asset_position) {
59 | var link_object = link_array.get_object_element (asset_position);
60 |
61 | var download_url = link_object.get_string_member ("direct_asset_url").replace ("?ref_type=heads", "");
62 |
63 | var release = new Releases.Basic.gitlab (this, title, description, release_date, download_url, page_url);
64 |
65 | releases.append (release);
66 | temp_releases.append (release);
67 | }
68 | }
69 |
70 | return temp_releases;
71 | }
72 | }
73 | }
--------------------------------------------------------------------------------
/src/models/runners/kron4ek-wine-builds-staging-tkg.vala:
--------------------------------------------------------------------------------
1 | namespace ProtonPlus.Models.Runners {
2 | public class Wine_Staging_Tkg_Kron4ek : GitHub {
3 | public Wine_Staging_Tkg_Kron4ek (Group group) {
4 | var request_asset_exclude = new string[] { "proton", ".0." };
5 | Object (group: group,
6 | title: "Wine-Staging-Tkg (Kron4ek)",
7 | description: _("Wine build with the Staging patchset and many other useful patches."),
8 | endpoint: "https://api.github.com/repos/Kron4ek/Wine-Builds/releases",
9 | asset_position: 3,
10 | request_asset_exclude: request_asset_exclude);
11 | }
12 |
13 | public override string get_directory_name (string release_name) {
14 | return @"wine-$release_name-staging-tkg-amd64";
15 | }
16 | }
17 | }
--------------------------------------------------------------------------------
/src/models/runners/kron4ek-wine-builds-staging.vala:
--------------------------------------------------------------------------------
1 | namespace ProtonPlus.Models.Runners {
2 | public class Wine_Staging_Kron4ek : GitHub {
3 | public Wine_Staging_Kron4ek (Group group) {
4 | var request_asset_exclude = new string[] { "proton", ".0." };
5 | Object (group: group,
6 | title: "Wine-Staging (Kron4ek)",
7 | description: _("Wine build with the Staging patchset."),
8 | endpoint: "https://api.github.com/repos/Kron4ek/Wine-Builds/releases",
9 | asset_position: 2,
10 | request_asset_exclude: request_asset_exclude);
11 | // https://api.github.com/repos/Kron4ek/Wine-Builds/releases
12 | // 2
13 | // Models.Runner.title_types.KRON4EK_STAGING
14 | // kron4ek_staging.request_asset_exclude = { "proton", ".0." };
15 | }
16 |
17 | public override string get_directory_name (string release_name) {
18 | return @"wine-$release_name-staging-amd64";
19 | }
20 | }
21 | }
--------------------------------------------------------------------------------
/src/models/runners/kron4ek-wine-builds-vanilla.vala:
--------------------------------------------------------------------------------
1 | namespace ProtonPlus.Models.Runners {
2 | public class Wine_Vanilla_Kron4ek : GitHub {
3 | public Wine_Vanilla_Kron4ek (Group group) {
4 | var request_asset_exclude = new string[] { "proton", ".0." };
5 | Object (group: group,
6 | title: "Wine-Vanilla (Kron4ek)",
7 | description: _("Wine build compiled from the official WineHQ sources."),
8 | endpoint: "https://api.github.com/repos/Kron4ek/Wine-Builds/releases",
9 | asset_position: 1,
10 | request_asset_exclude: request_asset_exclude);
11 | }
12 |
13 | public override string get_directory_name (string release_name) {
14 | return @"wine-$release_name-amd64";
15 | }
16 | }
17 | }
--------------------------------------------------------------------------------
/src/models/runners/luxtorpeda.vala:
--------------------------------------------------------------------------------
1 | namespace ProtonPlus.Models.Runners {
2 | public class Luxtorpeda : GitHub {
3 | public Luxtorpeda (Group group) {
4 | Object (group: group,
5 | title: "Luxtorpeda",
6 | description: _("Luxtorpeda provides Linux-native game engines for certain Windows-only games."),
7 | endpoint: "https://api.github.com/repos/luxtorpeda-dev/luxtorpeda/releases",
8 | asset_position: 0);
9 | }
10 |
11 | public override string get_directory_name (string release_name) {
12 | return @"$title $release_name";
13 | }
14 | }
15 | }
--------------------------------------------------------------------------------
/src/models/runners/northstar-proton.vala:
--------------------------------------------------------------------------------
1 | namespace ProtonPlus.Models.Runners {
2 | public class Northstar_Proton : GitHub {
3 | public Northstar_Proton (Group group) {
4 | Object (group: group,
5 | title: "NorthstarProton",
6 | description: _("Custom Proton build for running the Northstar client for Titanfall 2."),
7 | endpoint: "https://api.github.com/repos/cyrv6737/NorthstarProton/releases",
8 | asset_position: 0);
9 | }
10 |
11 | public override string get_directory_name (string release_name) {
12 | return @"$title $release_name";
13 | }
14 | }
15 | }
--------------------------------------------------------------------------------
/src/models/runners/other.vala:
--------------------------------------------------------------------------------
1 | namespace ProtonPlus.Models.Runners {
2 | public class Other : GitHub {
3 | public Other (Group group) {
4 | Object (group: group,
5 | title: "Other",
6 | description: "",
7 | endpoint: "https://api.github.com/repos/bottlesdevs/wine/releases",
8 | asset_position: 0,
9 | use_name_instead_of_tag_name: true);
10 | }
11 |
12 | public override string get_directory_name (string release_name) {
13 | return release_name.down ().replace (" ", "-");
14 | }
15 | }
16 | }
--------------------------------------------------------------------------------
/src/models/runners/proton-cachyos.vala:
--------------------------------------------------------------------------------
1 | namespace ProtonPlus.Models.Runners {
2 | public class Proton_CachyOS : GitHub {
3 | public Proton_CachyOS (Group group) {
4 | int position = 1;
5 | foreach (var item in Utils.System.HWCAPS) {
6 | if (item == "x86_64_v3") {
7 | position = 3;
8 | break;
9 | }
10 | }
11 |
12 | Object (group: group,
13 | title: "Proton-CachyOS",
14 | description: _("Steam compatibility tool from the CachyOS Linux distribution for running Windows games with improvements over Valve's default Proton."),
15 | endpoint: "https://api.github.com/repos/CachyOS/proton-cachyos/releases",
16 | asset_position: position);
17 | }
18 |
19 | public override string get_directory_name (string release_name) {
20 | return @"$title $release_name";
21 | }
22 | }
23 | }
--------------------------------------------------------------------------------
/src/models/runners/proton-em.vala:
--------------------------------------------------------------------------------
1 | namespace ProtonPlus.Models.Runners {
2 | public class Proton_EM : GitHub {
3 | public Proton_EM (Group group) {
4 | Object (group: group,
5 | title: "Proton-EM",
6 | description: _("Steam compatibility tool for running Windows games with improvements over Valve's default Proton. By Etaash Mathamsetty adding FSR4 support and wine wayland tweaks."),
7 | endpoint: "https://api.github.com/repos/Etaash-mathamsetty/Proton/releases",
8 | asset_position: 1);
9 | }
10 |
11 | public override string get_directory_name (string release_name) {
12 | return release_name;
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/models/runners/proton-ge-rstp.vala:
--------------------------------------------------------------------------------
1 | namespace ProtonPlus.Models.Runners {
2 | public class Proton_GE_RSTP : GitHub {
3 | public Proton_GE_RSTP (Group group) {
4 | Object (group: group,
5 | title: "Proton-GE RTSP",
6 | description: _("Steam compatibility tool based on Proton-GE with additional patches to improve RTSP codecs for VRChat."),
7 | endpoint: "https://api.github.com/repos/SpookySkeletons/proton-ge-rtsp/releases",
8 | asset_position: 0);
9 | }
10 |
11 | public override string get_directory_name (string release_name) {
12 | return @"$title $release_name";
13 | }
14 | }
15 | }
--------------------------------------------------------------------------------
/src/models/runners/proton-ge.vala:
--------------------------------------------------------------------------------
1 | namespace ProtonPlus.Models.Runners {
2 | public class Proton_GE : GitHub {
3 | public Proton_GE (Group group) {
4 | Object (group: group,
5 | title: "Proton-GE",
6 | description: _("Steam compatibility tool for running Windows games with improvements over Valve's default Proton."),
7 | endpoint: "https://api.github.com/repos/GloriousEggroll/proton-ge-custom/releases",
8 | asset_position: 1);
9 | }
10 |
11 | public override string get_directory_name (string release_name) {
12 | switch (group.launcher.title) {
13 | case "Steam":
14 | if (title.contains (".")) {
15 | return "Proton-" + release_name;
16 | }
17 | return release_name;
18 | case "Bottles":
19 | return release_name.down ();
20 |
21 | case "Heroic Games Launcher":
22 | return @"Proton-$release_name";
23 | default:
24 | return release_name;
25 | }
26 | }
27 | }
28 | }
--------------------------------------------------------------------------------
/src/models/runners/proton-sarek-async.vala:
--------------------------------------------------------------------------------
1 | namespace ProtonPlus.Models.Runners {
2 | public class Proton_Sarek_Async : GitHub {
3 | public Proton_Sarek_Async (Group group) {
4 | Object (group: group,
5 | title: "Proton-Sarek (Async)",
6 | description: _("Steam compatibility tool based on Proton-GE with modifications for very old GPUs, with %s.").printf ("DXVK-Async"),
7 | endpoint: "https://api.github.com/repos/pythonlover02/Proton-Sarek/releases",
8 | asset_position: 0,
9 | request_asset_exclude: new string[] { "Sarek9-13" });
10 | }
11 |
12 | public override string get_directory_name (string release_name) {
13 | return release_name + "-async";
14 | }
15 | }
16 | }
--------------------------------------------------------------------------------
/src/models/runners/proton-sarek.vala:
--------------------------------------------------------------------------------
1 | namespace ProtonPlus.Models.Runners {
2 | public class Proton_Sarek : GitHub {
3 | public Proton_Sarek (Group group) {
4 | Object (group: group,
5 | title: "Proton-Sarek",
6 | description: _("Steam compatibility tool based on Proton-GE with modifications for very old GPUs, with %s.").printf ("DXVK"),
7 | endpoint: "https://api.github.com/repos/pythonlover02/Proton-Sarek/releases",
8 | asset_position: 1,
9 | request_asset_exclude: new string[] { "Sarek9-13" });
10 | }
11 |
12 | public override string get_directory_name (string release_name) {
13 | return release_name;
14 | }
15 | }
16 | }
--------------------------------------------------------------------------------
/src/models/runners/proton-tkg.vala:
--------------------------------------------------------------------------------
1 | namespace ProtonPlus.Models.Runners {
2 | public class Proton_Tkg : GitHubAction {
3 | public Proton_Tkg (Group group) {
4 | Object (group: group,
5 | title: "Proton-Tkg",
6 | description: _("Custom Proton build for running Windows games, based on Wine-tkg."),
7 | endpoint: "https://api.github.com/repos/Frogging-Family/wine-tkg-git/actions/workflows/29873769/runs",
8 | asset_position: 0,
9 | url_template: "https://nightly.link/Frogging-Family/wine-tkg-git/actions/runs/{id}/proton-tkg-build.zip");
10 | }
11 |
12 | public override string get_directory_name (string release_name) {
13 | return @"$title-$release_name";
14 | }
15 | }
16 | }
--------------------------------------------------------------------------------
/src/models/runners/roberta.vala:
--------------------------------------------------------------------------------
1 | namespace ProtonPlus.Models.Runners {
2 | public class Roberta : GitHub {
3 | public Roberta (Group group) {
4 | Object (group: group,
5 | title: "Roberta",
6 | description: _("Steam compatibility tool for running adventure games using ScummVM for Linux."),
7 | endpoint: "https://api.github.com/repos/dreamer/roberta/releases",
8 | asset_position: 0);
9 | }
10 |
11 | public override string get_directory_name (string release_name) {
12 | return @"$title $release_name";
13 | }
14 | }
15 | }
--------------------------------------------------------------------------------
/src/models/runners/steamtinkerlaunch.vala:
--------------------------------------------------------------------------------
1 | namespace ProtonPlus.Models.Runners {
2 | public class SteamTinkerLaunch : Runner {
3 | public SteamTinkerLaunch (Models.Group group) {
4 | Object (group: group,
5 | title: "SteamTinkerLaunch",
6 | description: _("Steam tool for easy, graphical configuration of your other compatibility tools for both Windows games and native Linux games."));
7 | }
8 |
9 | public override async List load () {
10 | releases = new List ();
11 |
12 | var release = new Releases.SteamTinkerLaunch (this);
13 |
14 | releases.append (release);
15 |
16 | return (owned) releases;
17 | }
18 | }
19 | }
--------------------------------------------------------------------------------
/src/models/runners/vkd3d-lutris.vala:
--------------------------------------------------------------------------------
1 | namespace ProtonPlus.Models.Runners {
2 | public class VKD3D_Lutris : GitHub {
3 | public VKD3D_Lutris (Group group) {
4 | Object (group: group,
5 | title: "VKD3D-Lutris",
6 | description: "",
7 | endpoint: "https://api.github.com/repos/lutris/vkd3d/releases",
8 | asset_position: 0);
9 | }
10 |
11 | public override string get_directory_name (string release_name) {
12 | switch (group.launcher.title) {
13 | case "Lutris":
14 | return release_name;
15 | case "Heroic Games Launcher":
16 | return release_name.replace ("v", "vkd3d-lutris-");
17 | default:
18 | return release_name;
19 | }
20 | }
21 | }
22 | }
--------------------------------------------------------------------------------
/src/models/runners/vkd3d-proton.vala:
--------------------------------------------------------------------------------
1 | namespace ProtonPlus.Models.Runners {
2 | public class VKD3D_Proton : GitHub {
3 | public VKD3D_Proton (Group group) {
4 | Object (group: group,
5 | title: "VKD3D-Proton",
6 | description: "",
7 | endpoint: "https://api.github.com/repos/HansKristian-Work/vkd3d-proton/releases",
8 | asset_position: 0);
9 | }
10 |
11 | public override string get_directory_name (string release_name) {
12 | return release_name.replace ("v", "vkd3d-proton-");
13 | }
14 | }
15 | }
--------------------------------------------------------------------------------
/src/utils/parser.vala:
--------------------------------------------------------------------------------
1 | namespace ProtonPlus.Utils {
2 | public class Parser {
3 | public static Json.Node? get_node_from_json (string json) {
4 | try {
5 | return Json.from_string (json);
6 | } catch (Error e) {
7 | message (e.message);
8 | return null;
9 | }
10 | }
11 | }
12 | }
--------------------------------------------------------------------------------
/src/utils/system.vala:
--------------------------------------------------------------------------------
1 | namespace ProtonPlus.Utils {
2 | public class System {
3 | public static bool IS_STEAM_OS = false;
4 | public static bool IS_GAMESCOPE = false;
5 | public static bool IS_FLATPAK = false;
6 | public static List HWCAPS = new List ();
7 |
8 | public static void initialize () {
9 | IS_FLATPAK = FileUtils.test ("/.flatpak-info", FileTest.IS_REGULAR);
10 | IS_GAMESCOPE = Environment.get_variable ("DESKTOP_SESSION") == "gamescope-wayland";
11 | IS_STEAM_OS = get_distribution_name ().ascii_down () == "steamos";
12 | HWCAPS = get_hwcaps ();
13 | }
14 |
15 | public static string run_command (string command) {
16 | try {
17 | string command_line = "";
18 | if (IS_FLATPAK)command_line += "flatpak-spawn --host ";
19 | command_line += command;
20 |
21 | string stdout = "";
22 | var valid = Process.spawn_command_line_sync (command_line, out stdout, null, null);
23 | if (!valid)return "";
24 |
25 | return stdout;
26 | } catch (Error e) {
27 | message (e.message);
28 | return "";
29 | }
30 | }
31 |
32 | public static List get_hwcaps () {
33 | var hwcaps = new List ();
34 | hwcaps.append ("x86_64");
35 |
36 | // flags according to https://gitlab.com/x86-psABIs/x86-64-ABI/-/blob/master/x86-64-ABI/low-level-sys-info.tex
37 | var flags_v2 = new List ();
38 | flags_v2.append ("sse4_1");
39 | flags_v2.append ("sse4_2");
40 | flags_v2.append ("ssse3");
41 |
42 | var flags_v3 = new List ();
43 | foreach (var flag in flags_v2)
44 | flags_v3.append (flag);
45 | flags_v3.append ("avx");
46 | flags_v3.append ("avx2");
47 |
48 | var flags_v4 = new List ();
49 | foreach (var flag in flags_v3)
50 | flags_v4.append (flag);
51 | flags_v4.append ("avx512f");
52 | flags_v4.append ("avx512bw");
53 | flags_v4.append ("avx512cd");
54 | flags_v4.append ("avx512dq");
55 | flags_v4.append ("avx512vl");
56 |
57 | string flags = "";
58 |
59 | try {
60 | // Open the file for reading
61 | File file = File.new_for_path ("/proc/cpuinfo");
62 | InputStream input_stream = file.read ();
63 | DataInputStream dis = new DataInputStream (input_stream);
64 |
65 | // Read lines from the input stream
66 | string? line;
67 | while ((line = dis.read_line ()) != null) {
68 | if (line.slice (0, 5) == "flags") {
69 | flags = line;
70 | break;
71 | }
72 | }
73 |
74 | // Close the input stream
75 | input_stream.close ();
76 | } catch (Error e) {
77 | message ("Error: %s\n", e.message);
78 | }
79 |
80 | int count = 0;
81 | foreach (var flag in flags_v4) {
82 | if (flags.contains (flag))
83 | count++;
84 | }
85 | if (flags_v4.length () == count)
86 | hwcaps.append ("x86_64_v4");
87 |
88 | count = 0;
89 | foreach (var flag in flags_v3) {
90 | if (flags.contains (flag))
91 | count++;
92 | }
93 | if (flags_v3.length () == count)
94 | hwcaps.append ("x86_64_v3");
95 |
96 | count = 0;
97 | foreach (var flag in flags_v2) {
98 | if (flags.contains (flag))
99 | count++;
100 | }
101 | if (flags_v2.length () == count)
102 | hwcaps.append ("x86_64_v2");
103 |
104 | return (owned) hwcaps;
105 | }
106 |
107 | public static bool check_dependency (string name) {
108 | return run_command (@"which $name") == "" ? false : true;
109 | }
110 |
111 | static string get_distribution_name () {
112 | var distro_info = run_command ("cat /etc/lsb-release /etc/os-release").split ("\n", 1)[0];
113 |
114 | var distro_name = "Unknown";
115 | MatchInfo m;
116 | if (/^NAME="\s*(.+?)\s*"/m.match (distro_info, 0, out m))
117 | distro_name = m.fetch (1);
118 |
119 | return distro_name;
120 | }
121 |
122 | public static void open_url (string url) {
123 | var uri_launcher = new Gtk.UriLauncher (url);
124 | uri_launcher.launch.begin (Widgets.Application.window, null, (obj, res) => {
125 | try {
126 | uri_launcher.launch.end (res);
127 | } catch (Error error) {
128 | message (error.message);
129 | }
130 | });
131 | }
132 | }
133 | }
--------------------------------------------------------------------------------
/src/utils/web.vala:
--------------------------------------------------------------------------------
1 | namespace ProtonPlus.Utils {
2 | public class Web {
3 | public static string get_user_agent () {
4 | return Config.APP_NAME + "/" + Config.APP_VERSION;
5 | }
6 |
7 | public static async string ? GET (string url, bool stl = false) {
8 | try {
9 | var session = new Soup.Session ();
10 | session.set_user_agent (get_user_agent ());
11 |
12 | var message = new Soup.Message ("GET", url);
13 |
14 | Bytes bytes = yield session.send_and_read_async (message, Priority.DEFAULT, null);
15 |
16 | return (string) bytes.get_data ();
17 | } catch (Error e) {
18 | message (e.message);
19 | return null;
20 | }
21 | }
22 |
23 | public delegate bool cancel_callback ();
24 |
25 | public delegate void progress_callback (bool is_percent, int64 progress);
26 |
27 | public static async bool Download (string url, string path, cancel_callback cancel_callback, progress_callback progress_callback) {
28 | try {
29 | var session = new Soup.Session ();
30 | session.set_user_agent (get_user_agent ());
31 |
32 | var soup_message = new Soup.Message ("GET", url);
33 |
34 | var input_stream = yield session.send_async (soup_message, Priority.DEFAULT, null);
35 |
36 | if (soup_message.status_code != 200) {
37 | message (soup_message.reason_phrase);
38 | return false;
39 | }
40 |
41 | var file = File.new_for_path (path);
42 | if (file.query_exists ())
43 | yield file.delete_async (Priority.DEFAULT, null);
44 |
45 | FileOutputStream output_stream = yield file.create_async (FileCreateFlags.REPLACE_DESTINATION, Priority.DEFAULT, null);
46 |
47 | // Prefer real Content-Length header from the server if it exists.
48 | // NOTE: Servers typically return "0" when it doesn't know, for
49 | // live-generated files (such as GitHub's commit-based source
50 | // archives). However, GitHub's server then caches the generated
51 | // result for a few minutes to avoid extra work. So the first
52 | // download of a GitHub source archive will have an unknown "0"
53 | // length, but any download requests after that it will see the
54 | // filesize for a few minutes, until GitHub clears their cache.
55 | int64 server_download_size = soup_message.get_response_headers ().get_content_length ();
56 |
57 | const size_t chunk_size = 4096;
58 | bool is_percent = server_download_size > 0;
59 | int64 bytes_downloaded = 0;
60 |
61 | if (progress_callback != null)
62 | progress_callback (is_percent, 0); // Set initial progress state.
63 |
64 | var is_canceled = false;
65 |
66 | while (true) {
67 | if (cancel_callback ()) {
68 | is_canceled = true;
69 | break;
70 | }
71 |
72 | var chunk = yield input_stream.read_bytes_async (chunk_size);
73 |
74 | if (chunk.get_size () == 0)
75 | break;
76 |
77 | bytes_downloaded += output_stream.write (chunk.get_data ());
78 |
79 | if (progress_callback != null) {
80 | // Use "bytes downloaded" when total size is unknown.
81 | int64 progress = !is_percent ? bytes_downloaded : (int64) (((double) bytes_downloaded / server_download_size) * 100);
82 | progress_callback (is_percent, progress);
83 | }
84 | }
85 |
86 | yield output_stream.close_async ();
87 |
88 | session.abort ();
89 |
90 | if (is_canceled && file.query_exists ())
91 | yield file.delete_async (Priority.DEFAULT, null);
92 |
93 | return !is_canceled;
94 | } catch (Error e) {
95 | message (e.message);
96 | return false;
97 | }
98 | }
99 | }
100 | }
--------------------------------------------------------------------------------
/src/widgets/application.vala:
--------------------------------------------------------------------------------
1 | namespace ProtonPlus.Widgets {
2 | public class Application : Adw.Application {
3 | public static Window window { get; set; }
4 |
5 | construct {
6 | application_id = Config.APP_ID;
7 | flags |= ApplicationFlags.FLAGS_NONE;
8 |
9 | ActionEntry[] action_entries = {
10 | { "about", this.on_about_action },
11 | { "quit", this.quit }
12 | };
13 | this.add_action_entries (action_entries, this);
14 | this.set_accels_for_action ("app.quit", { "Q" });
15 | }
16 |
17 | public override void activate () {
18 | base.activate ();
19 |
20 | window = new Window ();
21 |
22 | var display = Gdk.Display.get_default ();
23 |
24 | Gtk.IconTheme.get_for_display (display).add_resource_path ("/com/vysp3r/ProtonPlus/icons");
25 |
26 | var css_provider = new Gtk.CssProvider ();
27 | css_provider.load_from_resource ("/com/vysp3r/ProtonPlus/css/style.css");
28 |
29 | Gtk.StyleContext.add_provider_for_display (display, css_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
30 |
31 | Utils.System.initialize ();
32 |
33 | window.initialize ();
34 |
35 | var settings = new Settings ("com.vysp3r.ProtonPlus.State");
36 | settings.bind ("width",
37 | window,
38 | "default-width",
39 | SettingsBindFlags.DEFAULT);
40 | settings.bind ("height",
41 | window,
42 | "default-height",
43 | SettingsBindFlags.DEFAULT);
44 | settings.bind ("is-maximized",
45 | window,
46 | "maximized",
47 | SettingsBindFlags.DEFAULT);
48 | settings.bind ("is-fullscreen",
49 | window,
50 | "fullscreened",
51 | SettingsBindFlags.DEFAULT);
52 |
53 | if (Utils.System.IS_GAMESCOPE)
54 | window.fullscreen ();
55 |
56 | window.present ();
57 | }
58 |
59 | void on_about_action () {
60 | const string[] devs = {
61 | "Charles Malouin (Vysp3r) https://github.com/Vysp3r",
62 | "Johnny Arcitec https://github.com/Arcitec",
63 | "windblows95 https://github.com/windblows95",
64 | null
65 | };
66 |
67 | const string[] thanks = {
68 | "GNOME Project https://www.gnome.org/",
69 | "ProtonUp-Qt Project https://davidotek.github.io/protonup-qt/",
70 | "LUG Helper Project https://github.com/starcitizen-lug/lug-helper",
71 | null
72 | };
73 |
74 | var about_dialog = new Adw.AboutDialog ();
75 | about_dialog.set_application_name (Config.APP_NAME);
76 | about_dialog.set_application_icon (Config.APP_ID);
77 | about_dialog.set_version ("v" + Config.APP_VERSION);
78 | about_dialog.set_comments (_("A modern compatibility tools manager for Linux."));
79 | about_dialog.add_link ("GitHub", "https://github.com/Vysp3r/ProtonPlus");
80 | about_dialog.add_link ("Website", "https://protonplus.vysp3r.com/");
81 | about_dialog.set_issue_url ("https://github.com/Vysp3r/ProtonPlus/issues/new/choose");
82 | about_dialog.set_copyright ("© 2022-2025 Vysp3r");
83 | about_dialog.set_license_type (Gtk.License.GPL_3_0);
84 | about_dialog.set_developers (devs);
85 | about_dialog.add_credit_section (_("Special thanks to"), thanks);
86 | about_dialog.present (window);
87 | }
88 | }
89 | }
--------------------------------------------------------------------------------
/src/widgets/busy-dialog.vala:
--------------------------------------------------------------------------------
1 | namespace ProtonPlus.Widgets {
2 | public abstract class BusyDialog : Adw.Dialog {
3 | protected Adw.ToolbarView toolbar_view { get; set; }
4 | protected Adw.WindowTitle window_title { get; set; }
5 | protected Adw.HeaderBar header_bar { get; set; }
6 | protected Gtk.Box content_box { get; set; }
7 | protected Gtk.ScrolledWindow scrolled_window { get; set; }
8 | protected Gtk.Box container { get; set; }
9 | protected Gtk.Label progress_label { get; set; }
10 | protected Gtk.Label closing_label { get; set; }
11 | protected Gtk.ProgressBar progress_bar { get; set; }
12 |
13 | protected Models.Release release { get; set; }
14 | protected bool pulse { get; set; }
15 | protected bool finished { get; set; }
16 | protected bool stop { get; set; }
17 | protected int count { get; set; }
18 |
19 | construct {
20 | window_title = new Adw.WindowTitle ("", "");
21 |
22 | var log_button = new Gtk.Button.from_icon_name ("journal-text-symbolic");
23 | log_button.set_tooltip_text (_("Show/hide logs"));
24 | log_button.clicked.connect (() => {
25 | if (scrolled_window.get_parent () == null)
26 | content_box.prepend (scrolled_window);
27 | else
28 | content_box.remove (scrolled_window);
29 | });
30 |
31 | header_bar = new Adw.HeaderBar ();
32 | header_bar.set_title_widget (window_title);
33 | header_bar.pack_start (log_button);
34 |
35 | progress_label = new Gtk.Label ("");
36 |
37 | closing_label = new Gtk.Label ("");
38 |
39 | container = new Gtk.Box (Gtk.Orientation.VERTICAL, 2);
40 |
41 | scrolled_window = new Gtk.ScrolledWindow ();
42 | scrolled_window.set_child (container);
43 | scrolled_window.set_size_request (200, 125);
44 | scrolled_window.set_policy (Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
45 | scrolled_window.add_css_class ("card");
46 | scrolled_window.add_css_class ("dialog");
47 | scrolled_window.get_vadjustment ().changed.connect (scroll_to_bottom);
48 |
49 | progress_bar = new Gtk.ProgressBar ();
50 | progress_bar.set_hexpand (true);
51 | progress_bar.set_vexpand (true);
52 | progress_bar.set_valign (Gtk.Align.CENTER);
53 | progress_bar.set_show_text (true);
54 |
55 | content_box = new Gtk.Box (Gtk.Orientation.VERTICAL, 12);
56 | content_box.set_margin_bottom (12);
57 | content_box.set_margin_start (12);
58 | content_box.set_margin_end (12);
59 | content_box.append (progress_bar);
60 |
61 | toolbar_view = new Adw.ToolbarView ();
62 | toolbar_view.add_top_bar (header_bar);
63 | toolbar_view.set_content (content_box);
64 |
65 | closed.connect (dialog_on_close);
66 |
67 | set_child (toolbar_view);
68 | }
69 |
70 | protected void initialize (Models.Release release) {
71 | this.release = release;
72 |
73 | header_bar.set_show_end_title_buttons (false);
74 |
75 | window_title.set_subtitle (release.displayed_title);
76 |
77 | Timeout.add_full (Priority.DEFAULT, 25, () => {
78 | if (finished || stop)
79 | return false;
80 |
81 | if (pulse)progress_bar.pulse ();
82 |
83 | return true;
84 | });
85 | }
86 |
87 | protected void dialog_on_close () {
88 | stop = true;
89 | }
90 |
91 | public virtual void done (bool success) {
92 | header_bar.set_show_end_title_buttons (true);
93 |
94 | finished = true;
95 | pulse = false;
96 | progress_bar.set_fraction (1);
97 |
98 | if (success) {
99 | count = 5;
100 |
101 | refresh_closing_label ();
102 |
103 | GLib.Timeout.add_seconds_full (Priority.DEFAULT, 1, () => {
104 | if (stop)
105 | return false;
106 |
107 | if (count == 0) {
108 | close ();
109 | return false;
110 | }
111 |
112 | refresh_closing_label ();
113 |
114 | return true;
115 | });
116 | }
117 | }
118 |
119 | void refresh_closing_label () {
120 | closing_label.set_text ("%s %i".printf (_("Closing in"), count--));
121 | if (closing_label.get_parent () == null)
122 | container.append (closing_label);
123 | }
124 |
125 | public void add_text (string text) {
126 | var label = new Gtk.Label (text);
127 | container.append (label);
128 | progress_bar.set_text (text);
129 | }
130 |
131 | void scroll_to_bottom () {
132 | var adjustment = scrolled_window.get_vadjustment ();
133 | adjustment.set_value (adjustment.get_upper () - adjustment.get_page_size ());
134 | }
135 | }
136 | }
--------------------------------------------------------------------------------
/src/widgets/busy-dialogs/install-dialog.vala:
--------------------------------------------------------------------------------
1 | namespace ProtonPlus.Widgets.Dialogs {
2 | public class InstallDialog : BusyDialog {
3 | public InstallDialog (Models.Release release) {
4 | initialize (release);
5 |
6 | window_title.set_title (_("Installing"));
7 |
8 | release.notify["progress"].connect (release_progress_changed);
9 |
10 | closed.connect (install_dialog_on_close);
11 | }
12 |
13 | void install_dialog_on_close () {
14 | dialog_on_close ();
15 |
16 | release.canceled = true;
17 | }
18 |
19 | void release_progress_changed () {
20 | progress_label.set_text (release.progress);
21 | if (progress_label.get_parent () == null)
22 | container.append (progress_label);
23 |
24 | progress_bar.set_fraction (double.parse (release.progress) / 100);
25 |
26 | pulse = progress_bar.get_fraction () == 1;
27 |
28 | header_bar.set_show_end_title_buttons (!pulse);
29 | }
30 | }
31 | }
--------------------------------------------------------------------------------
/src/widgets/busy-dialogs/remove-dialog.vala:
--------------------------------------------------------------------------------
1 | namespace ProtonPlus.Widgets.Dialogs {
2 | public class RemoveDialog : BusyDialog {
3 | public RemoveDialog (Models.Release release) {
4 | initialize (release);
5 |
6 | window_title.set_title (_("Removing"));
7 | }
8 | }
9 | }
--------------------------------------------------------------------------------
/src/widgets/busy-dialogs/upgrade-dialog.vala:
--------------------------------------------------------------------------------
1 | namespace ProtonPlus.Widgets.Dialogs {
2 | public class UpgradeDialog : BusyDialog {
3 | public UpgradeDialog (Models.Release release) {
4 | initialize (release);
5 |
6 | window_title.set_title (_("Upgrading"));
7 | }
8 | }
9 | }
--------------------------------------------------------------------------------
/src/widgets/description-dialog.vala:
--------------------------------------------------------------------------------
1 | namespace ProtonPlus.Widgets {
2 | public class DescriptionDialog : Adw.Dialog {
3 | Models.Release release { get; set; }
4 |
5 | Adw.ToolbarView toolbar_view { get; set; }
6 | Adw.WindowTitle window_title { get; set; }
7 | Adw.ButtonContent web_button_content { get; set; }
8 | Gtk.Button web_button { get; set; }
9 | Adw.HeaderBar header_bar { get; set; }
10 | Gtk.ScrolledWindow scrolled_window { get; set; }
11 | Gtk.Label description_label { get; set; }
12 |
13 | construct {
14 | window_title = new Adw.WindowTitle (_("More information"), "");
15 |
16 | web_button_content = new Adw.ButtonContent ();
17 | web_button_content.set_icon_name ("world-www-symbolic");
18 | web_button_content.set_label (_("Open"));
19 |
20 | web_button = new Gtk.Button ();
21 | web_button.set_child (web_button_content);
22 | web_button.set_tooltip_text (_("Open in your web browser"));
23 | web_button.clicked.connect (web_button_clicked);
24 |
25 | header_bar = new Adw.HeaderBar ();
26 | header_bar.pack_start (web_button);
27 | header_bar.set_title_widget (window_title);
28 |
29 | description_label = new Gtk.Label (null);
30 | description_label.set_halign (Gtk.Align.START);
31 |
32 | scrolled_window = new Gtk.ScrolledWindow ();
33 | scrolled_window.set_child (description_label);
34 | scrolled_window.set_policy (Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC);
35 | scrolled_window.set_size_request (375, 175);
36 | scrolled_window.add_css_class ("card");
37 | scrolled_window.add_css_class ("dialog");
38 | scrolled_window.set_margin_top (7);
39 | scrolled_window.set_margin_bottom (12);
40 | scrolled_window.set_margin_start (12);
41 | scrolled_window.set_margin_end (12);
42 |
43 | toolbar_view = new Adw.ToolbarView ();
44 | toolbar_view.add_top_bar (header_bar);
45 | toolbar_view.set_content (scrolled_window);
46 |
47 | set_child (toolbar_view);
48 | }
49 |
50 | public DescriptionDialog (Models.Release release) {
51 | this.release = release;
52 |
53 | window_title.set_subtitle (release.displayed_title);
54 | description_label.set_label (release.description);
55 | }
56 |
57 | void web_button_clicked () {
58 | Utils.System.open_url (release.page_url);
59 | }
60 | }
61 | }
--------------------------------------------------------------------------------
/src/widgets/info-box.vala:
--------------------------------------------------------------------------------
1 | namespace ProtonPlus.Widgets {
2 | public class InfoBox : Gtk.Box {
3 | Menu menu { get; set; }
4 | Gtk.MenuButton menu_button { get; set; }
5 | Adw.WindowTitle window_title { get; set; }
6 | Adw.HeaderBar header { get; set; }
7 | Adw.ToolbarView toolbar_view { get; set; }
8 |
9 | public List launcher_boxes;
10 |
11 | construct {
12 | set_orientation (Gtk.Orientation.VERTICAL);
13 |
14 | window_title = new Adw.WindowTitle ("", "");
15 |
16 | var item = new MenuItem (_("_Installed Only"), null);
17 | item.set_action_and_target ("win.set-installed-only", "b");
18 |
19 | var filters_section = new Menu ();
20 | filters_section.append_item (item);
21 |
22 | var other_section = new Menu ();
23 | other_section.append (_("_Keyboard Shortcuts"), "win.show-help-overlay");
24 | other_section.append (_("_About ProtonPlus"), "app.about");
25 |
26 | menu = new Menu ();
27 | menu.append_section (null, filters_section);
28 | menu.append_section (null, other_section);
29 |
30 | menu_button = new Gtk.MenuButton ();
31 | menu_button.set_tooltip_text (_("Main Menu"));
32 | menu_button.set_icon_name ("open-menu-symbolic");
33 | menu_button.set_menu_model (menu);
34 |
35 | header = new Adw.HeaderBar ();
36 | header.set_title_widget (window_title);
37 | header.pack_end (menu_button);
38 |
39 | toolbar_view = new Adw.ToolbarView ();
40 | toolbar_view.add_top_bar (header);
41 |
42 | launcher_boxes = new List ();
43 |
44 | append (toolbar_view);
45 | }
46 |
47 | public void switch_mode (bool mode) {
48 | foreach (var box in launcher_boxes) {
49 | box.switch_mode (mode);
50 | }
51 | }
52 |
53 | public void switch_launcher (string title, int position) {
54 | window_title.set_title (title);
55 |
56 | var current_launcher_box = launcher_boxes.nth_data (position);
57 |
58 | if (current_launcher_box.get_parent () == null)
59 | toolbar_view.set_content (current_launcher_box);
60 | }
61 |
62 | public void initialize (List launchers) {
63 | foreach (var launcher in launchers) {
64 | var launcher_box = new Widgets.LauncherBox (launcher);
65 | launcher_boxes.append (launcher_box);
66 | }
67 | }
68 | }
69 | }
--------------------------------------------------------------------------------
/src/widgets/launcher-box.vala:
--------------------------------------------------------------------------------
1 | namespace ProtonPlus.Widgets {
2 | public class LauncherBox : Gtk.Widget {
3 | Models.Launcher launcher { get; set; }
4 | Gtk.BinLayout bin_layout { get; set; }
5 | Gtk.Box content { get; set; }
6 | Adw.Clamp clamp { get; set; }
7 | Gtk.ScrolledWindow scrolled_window { get; set; }
8 | List runner_groups;
9 |
10 | public LauncherBox (Models.Launcher launcher) {
11 | this.launcher = launcher;
12 |
13 | set_vexpand (true);
14 | set_margin_start (15);
15 | set_margin_end (15);
16 | set_margin_bottom (15);
17 |
18 | bin_layout = new Gtk.BinLayout ();
19 | set_layout_manager (bin_layout);
20 |
21 | content = new Gtk.Box (Gtk.Orientation.VERTICAL, 15);
22 |
23 | clamp = new Adw.Clamp ();
24 | clamp.set_maximum_size (700);
25 | clamp.set_child (content);
26 |
27 | scrolled_window = new Gtk.ScrolledWindow ();
28 | scrolled_window.set_child (clamp);
29 | scrolled_window.set_parent (this);
30 |
31 | runner_groups = new List ();
32 |
33 | foreach (var group in launcher.groups) {
34 | var runner_group = new RunnerGroup (group);
35 | runner_groups.append (runner_group);
36 | content.append (runner_group);
37 | }
38 | }
39 |
40 | public void switch_mode (bool mode) {
41 | foreach (var runner_group in runner_groups) {
42 | runner_group.load (mode);
43 | }
44 | }
45 | }
46 | }
--------------------------------------------------------------------------------
/src/widgets/load-more-row.vala:
--------------------------------------------------------------------------------
1 | namespace ProtonPlus.Widgets {
2 | public class LoadMoreRow : Adw.ActionRow {
3 | Gtk.Button load_button { get; set; }
4 | Gtk.Box suffix_box { get; set; }
5 |
6 | construct {
7 | load_button = new Gtk.Button.from_icon_name ("dots-symbolic");
8 | load_button.set_tooltip_text (_("Load more"));
9 | load_button.add_css_class ("flat");
10 | load_button.clicked.connect (() => activated ());
11 |
12 | suffix_box = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0);
13 | suffix_box.set_margin_end (10);
14 | suffix_box.set_valign (Gtk.Align.CENTER);
15 | suffix_box.append (load_button);
16 |
17 | set_title (_("Load more"));
18 | add_suffix (suffix_box);
19 | }
20 | }
21 | }
--------------------------------------------------------------------------------
/src/widgets/release-row.vala:
--------------------------------------------------------------------------------
1 | namespace ProtonPlus.Widgets {
2 | public abstract class ReleaseRow : Adw.ActionRow {
3 | protected Gtk.Button install_button { get; set; }
4 | protected Gtk.Button remove_button { get; set; }
5 | protected Gtk.Button info_button { get; set; }
6 | protected Gtk.Box input_box { get; set; }
7 |
8 | construct {
9 | remove_button = new Gtk.Button.from_icon_name ("trash-symbolic");
10 | remove_button.set_tooltip_text (_("Delete %s").printf (title));
11 | remove_button.add_css_class ("flat");
12 |
13 | install_button = new Gtk.Button.from_icon_name ("download-symbolic");
14 | install_button.set_tooltip_text (_("Install %s").printf (title));
15 | install_button.add_css_class ("flat");
16 |
17 | info_button = new Gtk.Button.from_icon_name ("info-circle-symbolic");
18 | info_button.set_tooltip_text (_("Show more information"));
19 | info_button.add_css_class ("flat");
20 |
21 | input_box = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 10);
22 | input_box.set_margin_end (10);
23 | input_box.set_valign (Gtk.Align.CENTER);
24 | input_box.append (info_button);
25 | input_box.append (remove_button);
26 | input_box.append (install_button);
27 |
28 | add_suffix (input_box);
29 |
30 | install_button.clicked.connect (install_button_clicked);
31 | remove_button.clicked.connect (remove_button_clicked);
32 | info_button.clicked.connect (info_button_clicked);
33 | }
34 |
35 | protected abstract void install_button_clicked ();
36 |
37 | protected abstract void remove_button_clicked ();
38 |
39 | protected abstract void info_button_clicked ();
40 | }
41 | }
--------------------------------------------------------------------------------
/src/widgets/release-rows/basic.vala:
--------------------------------------------------------------------------------
1 | namespace ProtonPlus.Widgets.ReleaseRows {
2 | public class Basic : ReleaseRow {
3 | Models.Releases.Basic release { get; set; }
4 |
5 | public Basic (Models.Releases.Basic release) {
6 | this.release = release;
7 |
8 | if (release.description == null || release.page_url == null)
9 | input_box.remove (info_button);
10 |
11 | release.notify["displayed-title"].connect (release_displayed_title_changed);
12 |
13 | release_displayed_title_changed ();
14 |
15 | release.notify["state"].connect (release_state_changed);
16 |
17 | release_state_changed ();
18 | }
19 |
20 | protected override void install_button_clicked () {
21 | var install_dialog = new Dialogs.InstallDialog (release);
22 | install_dialog.present (Application.window);
23 |
24 | release.send_message.connect (install_dialog.add_text);
25 |
26 | release.install.begin ((obj, res) => {
27 | var success = release.install.end (res);
28 |
29 | install_dialog.done (success || release.canceled);
30 | });
31 | }
32 |
33 | protected override void remove_button_clicked () {
34 | var alert_dialog = new Adw.AlertDialog (_("Delete %s").printf (release.title), "%s\n\n%s".printf (_("You're about to remove %s from your system.").printf (release.title), _("Are you sure you want this?")));
35 |
36 | alert_dialog.add_response ("no", _("No"));
37 | alert_dialog.add_response ("yes", _("Yes"));
38 |
39 | alert_dialog.set_response_appearance ("no", Adw.ResponseAppearance.DEFAULT);
40 | alert_dialog.set_response_appearance ("yes", Adw.ResponseAppearance.DESTRUCTIVE);
41 |
42 | alert_dialog.choose.begin (Application.window, null, (obj, res) => {
43 | var response = alert_dialog.choose.end (res);
44 |
45 | if (response != "yes")
46 | return;
47 |
48 | var remove_dialog = new Dialogs.RemoveDialog (release);
49 | remove_dialog.present (Application.window);
50 |
51 | release.send_message.connect (remove_dialog.add_text);
52 |
53 | release.remove.begin (new Models.Parameters (), (obj, res) => {
54 | var success = release.remove.end (res);
55 |
56 | remove_dialog.done (success);
57 | });
58 | });
59 | }
60 |
61 | protected override void info_button_clicked () {
62 | var description_dialog = new DescriptionDialog (release);
63 | description_dialog.present (Application.window);
64 | }
65 |
66 | void release_displayed_title_changed () {
67 | set_title (release.displayed_title);
68 | }
69 |
70 | void release_state_changed () {
71 | var installed = release.state == Models.Release.State.UP_TO_DATE;
72 |
73 | install_button.set_visible (!installed);
74 | remove_button.set_visible (installed);
75 | }
76 | }
77 | }
--------------------------------------------------------------------------------
/src/widgets/release-rows/steamtinkerlaunch.vala:
--------------------------------------------------------------------------------
1 | namespace ProtonPlus.Widgets.ReleaseRows {
2 | public class SteamTinkerLaunch : ReleaseRow {
3 | public Gtk.Button upgrade_button { get; set; }
4 |
5 | Models.Releases.SteamTinkerLaunch release;
6 |
7 | construct {
8 | upgrade_button = new Gtk.Button ();
9 | upgrade_button.add_css_class ("flat");
10 | upgrade_button.clicked.connect (upgrade_button_clicked);
11 |
12 | input_box.append (upgrade_button);
13 | }
14 |
15 | public SteamTinkerLaunch (Models.Releases.SteamTinkerLaunch release) {
16 | this.release = release;
17 |
18 | if (release.runner.group.launcher.installation_type != Models.Launcher.InstallationTypes.SYSTEM) {
19 | input_box.remove (install_button);
20 | input_box.remove (remove_button);
21 | input_box.remove (upgrade_button);
22 | } else {
23 | input_box.remove (info_button);
24 | }
25 |
26 | release.notify["displayed-title"].connect (release_displayed_title_changed);
27 |
28 | release_displayed_title_changed ();
29 |
30 | release.notify["state"].connect (release_state_changed);
31 |
32 | release_state_changed ();
33 | }
34 |
35 | protected override void install_button_clicked () {
36 | // Steam Deck doesn't need any external dependencies.
37 | if (!Utils.System.IS_STEAM_OS) {
38 | var missing_dependencies = "";
39 |
40 | var yad_installed = false;
41 | if (Utils.System.check_dependency ("yad")) {
42 | string stdout = Utils.System.run_command ("yad --version");
43 | float version = float.parse (stdout.split (" ")[0]);
44 | yad_installed = version >= 7.2;
45 | }
46 | if (!yad_installed)missing_dependencies += "yad >= 7.2\n";
47 |
48 | if (!Utils.System.check_dependency ("awk") && !Utils.System.check_dependency ("gawk"))missing_dependencies += "awk/gawk\n";
49 | if (!Utils.System.check_dependency ("git"))missing_dependencies += "git\n";
50 | if (!Utils.System.check_dependency ("pgrep"))missing_dependencies += "pgrep\n";
51 | if (!Utils.System.check_dependency ("unzip"))missing_dependencies += "unzip\n";
52 | if (!Utils.System.check_dependency ("wget"))missing_dependencies += "wget\n";
53 | if (!Utils.System.check_dependency ("xdotool"))missing_dependencies += "xdotool\n";
54 | if (!Utils.System.check_dependency ("xprop"))missing_dependencies += "xprop\n";
55 | if (!Utils.System.check_dependency ("xrandr"))missing_dependencies += "xrandr\n";
56 | if (!Utils.System.check_dependency ("xxd"))missing_dependencies += "xxd\n";
57 | if (!Utils.System.check_dependency ("xwininfo"))missing_dependencies += "xwininfo\n";
58 |
59 | if (missing_dependencies != "") {
60 | var alert_dialog = new Adw.AlertDialog (_("Missing dependencies!"), "%s\n\n%s\n%s".printf (_("You are missing the following dependencies for %s:").printf (title), missing_dependencies, _("Installation will be canceled.")));
61 |
62 | alert_dialog.add_response ("ok", _("OK"));
63 |
64 | alert_dialog.present (Widgets.Application.window);
65 |
66 | return;
67 | }
68 | }
69 |
70 | var has_external_install = release.detect_external_locations ();
71 |
72 | if (has_external_install) {
73 | var alert_dialog = new Adw.AlertDialog (_("Existing installation of %s").printf (title), "%s\n\n%s".printf (_("It looks like you currently have another version of %s which was not installed by ProtonPlus.").printf (title), _("Do you want to delete it and install %s with ProtonPlus?").printf (title)));
74 |
75 | alert_dialog.add_response ("cancel", _("Cancel"));
76 | alert_dialog.add_response ("ok", _("OK"));
77 |
78 | alert_dialog.set_response_appearance ("cancel", Adw.ResponseAppearance.DEFAULT);
79 | alert_dialog.set_response_appearance ("ok", Adw.ResponseAppearance.DESTRUCTIVE);
80 |
81 | alert_dialog.choose.begin (Widgets.Application.window, null, (obj, res) => {
82 | string response = alert_dialog.choose.end (res);
83 |
84 | if (response != "ok")
85 | return;
86 |
87 | start_install ();
88 | });
89 | } else {
90 | start_install ();
91 | }
92 | }
93 |
94 | void start_install () {
95 | var install_dialog = new Dialogs.InstallDialog (release);
96 | install_dialog.present (Application.window);
97 |
98 | release.send_message.connect (install_dialog.add_text);
99 |
100 | release.install.begin ((obj, res) => {
101 | var success = release.install.end (res);
102 |
103 | install_dialog.done (success);
104 | });
105 | }
106 |
107 | protected override void remove_button_clicked () {
108 | var remove_check = new Gtk.CheckButton.with_label (_("Check this to also remove your configuration files."));
109 |
110 | var alert_dialog = new Adw.AlertDialog (_("Delete %s").printf (release.title), "%s\n\n%s".printf (_("You're about to remove %s from your system.").printf (release.title), _("Are you sure you want this?")));
111 |
112 | alert_dialog.set_extra_child (remove_check);
113 |
114 | alert_dialog.add_response ("no", _("No"));
115 | alert_dialog.add_response ("yes", _("Yes"));
116 |
117 | alert_dialog.set_response_appearance ("no", Adw.ResponseAppearance.DEFAULT);
118 | alert_dialog.set_response_appearance ("yes", Adw.ResponseAppearance.DESTRUCTIVE);
119 |
120 | alert_dialog.response.connect ((response) => {
121 | if (response != "yes")
122 | return;
123 |
124 | var remove_dialog = new Dialogs.RemoveDialog (release);
125 | remove_dialog.present (Application.window);
126 |
127 | release.send_message.connect (remove_dialog.add_text);
128 |
129 | var parameters = new Models.Releases.SteamTinkerLaunch.STL_Remove_Parameters ();
130 | parameters.delete_config = remove_check.get_active ();
131 | parameters.user_request = true;
132 |
133 | release.remove.begin (parameters, (obj, res) => {
134 | var success = release.remove.end (res);
135 |
136 | remove_dialog.done (success);
137 | });
138 | });
139 |
140 | alert_dialog.present (Widgets.Application.window);
141 | }
142 |
143 | void upgrade_button_clicked () {
144 | if (release.state == Models.Release.State.UP_TO_DATE)
145 | return;
146 |
147 | var upgrade_dialog = new Dialogs.UpgradeDialog (release);
148 | upgrade_dialog.present (Application.window);
149 |
150 | release.send_message.connect (upgrade_dialog.add_text);
151 |
152 | release.upgrade.begin ((obj, res) => {
153 | var success = release.upgrade.end (res);
154 |
155 | upgrade_dialog.done (success);
156 | });
157 | }
158 |
159 | protected override void info_button_clicked () {
160 | Adw.AlertDialog? alert_dialog = null;
161 | switch (release.runner.group.launcher.installation_type) {
162 | case Models.Launcher.InstallationTypes.FLATPAK :
163 | var command_label = new Gtk.Label ("flatpak install com.valvesoftware.Steam.Utility.steamtinkerlaunch");
164 | command_label.set_selectable (true);
165 | alert_dialog = new Adw.AlertDialog (_("%s is not supported").printf ("Steam Flatpak"), _("To install %s for the %s, please run the following command:").printf (release.title, "Steam Flatpak"));
166 | alert_dialog.set_extra_child (command_label);
167 | break;
168 | case Models.Launcher.InstallationTypes.SNAP:
169 | alert_dialog = new Adw.AlertDialog (_("%s is not supported").printf ("Steam Snap"), _("There's currently no known way for us to install %s for the %s.").printf (release.title, "Steam Snap"));
170 | break;
171 | default:
172 | break;
173 | }
174 | if (alert_dialog != null) {
175 | alert_dialog.add_response ("ok", _("OK"));
176 |
177 | alert_dialog.present (Application.window);
178 | }
179 | }
180 |
181 | void release_displayed_title_changed () {
182 | set_title (release.displayed_title);
183 | }
184 |
185 | void release_state_changed () {
186 | var installed = release.state == Models.Release.State.UP_TO_DATE || release.state == Models.Release.State.UPDATE_AVAILABLE;
187 | var updated = release.state == Models.Release.State.UP_TO_DATE;
188 |
189 | install_button.set_visible (!installed);
190 | remove_button.set_visible (installed);
191 | upgrade_button.set_visible (installed);
192 |
193 | if (upgrade_button.get_visible ()) {
194 | upgrade_button.set_icon_name (updated ? "circle-check-symbolic" : "circle-chevron-up-symbolic");
195 | upgrade_button.set_tooltip_text (updated ? _("%s is up-to-date").printf (release.title) : _("Update %s to the latest version").printf (release.title));
196 | }
197 | }
198 | }
199 | }
--------------------------------------------------------------------------------
/src/widgets/runner-group.vala:
--------------------------------------------------------------------------------
1 | namespace ProtonPlus.Widgets {
2 | public class RunnerGroup : Adw.PreferencesGroup {
3 | List rows;
4 |
5 | public Models.Group group;
6 |
7 | public RunnerGroup(Models.Group group) {
8 | this.group = group;
9 |
10 | set_title(group.title);
11 | set_description(group.description);
12 |
13 | load(false);
14 | }
15 |
16 | public void load(bool installed_only) {
17 | clear();
18 |
19 | if (installed_only)
20 | load_installed_only();
21 | else
22 | load_normal();
23 | }
24 |
25 | void load_normal() {
26 | foreach (var runner in group.runners) {
27 | var runner_row = new RunnerRow(runner);
28 | add(runner_row);
29 | rows.append(runner_row);
30 | }
31 | }
32 |
33 | void load_installed_only() {
34 | try {
35 | var directory_path = group.launcher.directory + group.directory;
36 | File directory = File.new_for_path(directory_path);
37 | FileEnumerator? enumerator = directory.enumerate_children("standard::*", FileQueryInfoFlags.NONE, null);
38 |
39 | if (enumerator != null) {
40 | FileInfo? file_info;
41 | while ((file_info = enumerator.next_file()) != null) {
42 | if (file_info.get_file_type() != FileType.DIRECTORY)
43 | continue;
44 |
45 | var title = file_info.get_name();
46 | var runner = new Models.Runners.Proton_GE(group); // FIXME This should be replaced by it's own model instead of using Proton_GE
47 | var release = new Models.Releases.Basic.simple(runner, title, directory_path + "/" + title);
48 |
49 | var remove_button = new Gtk.Button.from_icon_name("trash-symbolic");
50 | remove_button.set_tooltip_text(_("Delete %s").printf(release.title));
51 | remove_button.add_css_class("flat");
52 |
53 | var input_box = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 10);
54 | input_box.set_valign(Gtk.Align.CENTER);
55 | input_box.append(remove_button);
56 |
57 | var row = new Adw.ActionRow();
58 | row.set_title(release.title);
59 | row.add_suffix(input_box);
60 |
61 | remove_button.clicked.connect(() => {
62 | var alert_dialog = new Adw.AlertDialog(_("Delete %s").printf(release.title), "%s\n\n%s".printf(_("You're about to remove %s from your system.").printf(release.title), _("Are you sure you want this?")));
63 |
64 | alert_dialog.add_response("no", _("No"));
65 | alert_dialog.add_response("yes", _("Yes"));
66 |
67 | alert_dialog.set_response_appearance("no", Adw.ResponseAppearance.DEFAULT);
68 | alert_dialog.set_response_appearance("yes", Adw.ResponseAppearance.DESTRUCTIVE);
69 |
70 | alert_dialog.choose.begin(Application.window, null, (obj, res) => {
71 | var response = alert_dialog.choose.end(res);
72 |
73 | if (response != "yes")
74 | return;
75 |
76 | var remove_dialog = new Dialogs.RemoveDialog(release);
77 | remove_dialog.present(Application.window);
78 |
79 | release.send_message.connect((message) => {
80 | switch (release.state) {
81 | case Models.Release.State.BUSY_INSTALLING :
82 | remove_dialog.add_text(message);
83 | break;
84 | case Models.Release.State.BUSY_REMOVING :
85 | remove_dialog.add_text(message);
86 | break;
87 | default:
88 | break;
89 | }
90 | });
91 |
92 | release.remove.begin(new Models.Parameters(), (obj, res) => {
93 | var success = release.remove.end(res);
94 |
95 | if (success)
96 | remove(row);
97 |
98 | remove_dialog.done(success);
99 | });
100 | });
101 | });
102 |
103 | add(row);
104 | rows.append(row);
105 | }
106 | }
107 | } catch (Error e) {
108 | message(e.message);
109 | }
110 | }
111 |
112 | void clear() {
113 | if (rows == null)return;
114 |
115 | foreach (var row in rows) {
116 | remove(row);
117 | }
118 |
119 | rows = new List ();
120 | }
121 | }
122 | }
--------------------------------------------------------------------------------
/src/widgets/runner-row.vala:
--------------------------------------------------------------------------------
1 | namespace ProtonPlus.Widgets {
2 | public class RunnerRow : Adw.ExpanderRow {
3 | Models.Runner runner { get; set; }
4 | Gtk.Spinner spinner { get; set; }
5 | LoadMoreRow load_more_row { get; set; }
6 |
7 | int count { get; set; }
8 |
9 | public RunnerRow (Models.Runner runner) {
10 | this.runner = runner;
11 |
12 | count = 0;
13 |
14 | load_more_row = new LoadMoreRow ();
15 | load_more_row.activated.connect (load_more_row_activated);
16 |
17 | spinner = new Gtk.Spinner ();
18 | spinner.set_visible (false);
19 |
20 | notify["expanded"].connect (() => expanded_changed (false));
21 |
22 | set_title (runner.title);
23 | set_subtitle (runner.description);
24 | add_suffix (spinner);
25 | }
26 |
27 | void expanded_changed (bool force_load = false) {
28 | if (get_expanded ()) {
29 | var a = runner.releases.length () == 0 || force_load;
30 | var b = runner.releases.length () >= 0 && count == 0;
31 | if (a || b) {
32 | spinner.start ();
33 | spinner.set_visible (true);
34 |
35 | if (a) {
36 | runner.load.begin ((obj, res) => {
37 | insert_loaded_releases (runner.load.end (res));
38 | });
39 | } else if (b) {
40 | insert_loaded_releases (runner.releases);
41 | }
42 | }
43 | }
44 | }
45 |
46 | void insert_loaded_releases (List releases) {
47 | foreach (var release in releases) {
48 | if (release is Models.Releases.Basic || release is Models.Releases.GitHubAction) {
49 | var row = new Widgets.ReleaseRows.Basic ((Models.Releases.Basic) release);
50 | add_row (row);
51 | } else if (release is Models.Releases.SteamTinkerLaunch) {
52 | var row = new Widgets.ReleaseRows.SteamTinkerLaunch ((Models.Releases.SteamTinkerLaunch) release);
53 | add_row (row);
54 | }
55 |
56 | count++;
57 | }
58 |
59 | if (runner.has_more)
60 | add_row (load_more_row);
61 |
62 | spinner.stop ();
63 | spinner.set_visible (false);
64 | }
65 |
66 | void load_more_row_activated () {
67 | remove (load_more_row);
68 | expanded_changed (true);
69 | }
70 | }
71 | }
--------------------------------------------------------------------------------
/src/widgets/sidebar-row.vala:
--------------------------------------------------------------------------------
1 | namespace ProtonPlus.Widgets {
2 | public class SidebarRow : Adw.ActionRow {
3 | Gtk.Image icon;
4 |
5 | public SidebarRow (string title, string type, string resource_path, string directory) {
6 | icon = new Gtk.Image.from_resource (resource_path);
7 | icon.set_pixel_size (48);
8 |
9 | add_prefix (icon);
10 | add_css_class ("sidebar-row");
11 | set_title (title);
12 | set_subtitle (type);
13 | set_activatable (true);
14 | set_tooltip_text (directory);
15 | }
16 | }
17 | }
--------------------------------------------------------------------------------
/src/widgets/sidebar.vala:
--------------------------------------------------------------------------------
1 | namespace ProtonPlus.Widgets {
2 | public class Sidebar : Gtk.Box {
3 | Gtk.ListBox list_box { get; set; }
4 | unowned List launchers;
5 | Models.Launcher selected_launcher;
6 |
7 | construct {
8 | var window_title = new Adw.WindowTitle ("ProtonPlus", "");
9 |
10 | var header_bar = new Adw.HeaderBar ();
11 | header_bar.set_title_widget (window_title);
12 |
13 | list_box = new Gtk.ListBox ();
14 | list_box.set_activate_on_single_click (true);
15 | list_box.set_selection_mode (Gtk.SelectionMode.SINGLE);
16 | list_box.add_css_class ("navigation-sidebar");
17 | list_box.set_hexpand (true);
18 | list_box.set_vexpand (true);
19 | list_box.row_activated.connect (list_box_row_activated);
20 | list_box.row_selected.connect (list_box_row_selected);
21 |
22 | var toolbar_view = new Adw.ToolbarView ();
23 | toolbar_view.add_top_bar (header_bar);
24 | toolbar_view.set_content (list_box);
25 |
26 | append (toolbar_view);
27 | }
28 |
29 | public void initialize (List launchers) {
30 | list_box.remove_all ();
31 |
32 | this.launchers = launchers;
33 |
34 | foreach (var launcher in launchers) {
35 | var row = new SidebarRow (launcher.title, launcher.get_installation_type_title (), launcher.icon_path, launcher.directory);
36 | list_box.append (row);
37 | }
38 | }
39 |
40 | void list_box_row_activated (Gtk.ListBoxRow? row) {
41 | activate_action_variant ("win.set-nav-view-active", true);
42 | }
43 |
44 | void list_box_row_selected (Gtk.ListBoxRow? row) {
45 | selected_launcher = launchers.nth_data (row.get_index ());
46 | activate_action_variant ("win.load-info-box", row.get_index ());
47 | }
48 | }
49 | }
--------------------------------------------------------------------------------
/src/widgets/status-box.vala:
--------------------------------------------------------------------------------
1 | namespace ProtonPlus.Widgets {
2 | public class StatusBox : Gtk.Box {
3 | Adw.ToolbarView toolbar_view { get; set; }
4 | Adw.HeaderBar header_bar { get; set; }
5 | Adw.StatusPage status_page { get; set; }
6 |
7 | construct {
8 | header_bar = new Adw.HeaderBar ();
9 | header_bar.add_css_class ("flat");
10 |
11 | status_page = new Adw.StatusPage ();
12 | status_page.set_vexpand (true);
13 | status_page.set_hexpand (true);
14 |
15 | toolbar_view = new Adw.ToolbarView ();
16 | toolbar_view.add_top_bar (header_bar);
17 | toolbar_view.set_content (status_page);
18 |
19 | append (toolbar_view);
20 | }
21 |
22 | public void initialize (string? icon_name, string title, string description) {
23 | status_page.set_icon_name (icon_name);
24 | status_page.set_title (title);
25 | status_page.set_description (description);
26 | }
27 | }
28 | }
--------------------------------------------------------------------------------
/src/widgets/window.vala:
--------------------------------------------------------------------------------
1 | namespace ProtonPlus.Widgets {
2 | public class Window : Adw.ApplicationWindow {
3 | List launchers;
4 |
5 | Adw.NavigationSplitView navigation_split_view { get; set; }
6 | Adw.NavigationPage info_page { get; set; }
7 | Adw.NavigationPage sidebar_page { get; set; }
8 | Widgets.StatusBox status_box { get; set; }
9 | Widgets.InfoBox info_box { get; set; }
10 | Widgets.Sidebar sidebar { get; set; }
11 | Adw.Breakpoint breakpoint { get; set; }
12 |
13 | construct {
14 | set_application ((Adw.Application) GLib.Application.get_default ());
15 | set_title (Config.APP_NAME);
16 |
17 | add_action (set_nav_view_active ());
18 | add_action (load_info_box ());
19 | add_action (set_installed_only ());
20 |
21 | set_size_request (460, 600);
22 |
23 | status_box = new Widgets.StatusBox ();
24 |
25 | info_page = new Adw.NavigationPage.with_tag (info_box = new Widgets.InfoBox (), "InfoBox", "main");
26 |
27 | sidebar_page = new Adw.NavigationPage.with_tag (sidebar = new Widgets.Sidebar (), "Sidebar", "sidebar");
28 |
29 | navigation_split_view = new Adw.NavigationSplitView ();
30 | navigation_split_view.set_sidebar (sidebar_page);
31 | navigation_split_view.set_content (info_page);
32 | navigation_split_view.set_show_content (true);
33 |
34 | breakpoint = new Adw.Breakpoint (Adw.BreakpointCondition.parse ("max-width: 660px"));
35 | breakpoint.add_setter (navigation_split_view, "collapsed", true);
36 |
37 | add_breakpoint (breakpoint);
38 | }
39 |
40 | public void initialize () {
41 | launchers = Models.Launcher.get_all ();
42 |
43 | if (launchers.length () > 0) {
44 | info_box.initialize (launchers);
45 | sidebar.initialize (launchers);
46 |
47 | if (navigation_split_view.get_parent () == null)
48 | set_content (navigation_split_view);
49 | } else {
50 | status_box.initialize (null, _("Welcome to %s").printf (Config.APP_NAME), _("Install Steam, Lutris, Bottles or Heroic Games Launcher to get started."));
51 |
52 | if (status_box.get_parent () == null)
53 | set_content (status_box);
54 |
55 | Timeout.add (10000, () => {
56 | initialize ();
57 |
58 | return false;
59 | });
60 | }
61 | }
62 |
63 | SimpleAction set_installed_only () {
64 | SimpleAction action = new SimpleAction.stateful ("set-installed-only", VariantType.BOOLEAN, true);
65 |
66 | action.activate.connect ((variant) => {
67 | action.set_state (!action.get_state ().get_boolean ());
68 | info_box.switch_mode (!action.get_state ().get_boolean ());
69 | });
70 |
71 | return action;
72 | }
73 |
74 | SimpleAction set_nav_view_active () {
75 | SimpleAction action = new SimpleAction ("set-nav-view-active", VariantType.BOOLEAN);
76 |
77 | action.activate.connect ((variant) => {
78 | navigation_split_view.set_show_content (variant.get_boolean ());
79 | });
80 |
81 | return action;
82 | }
83 |
84 | SimpleAction load_info_box () {
85 | SimpleAction action = new SimpleAction ("load-info-box", VariantType.INT32);
86 |
87 | action.activate.connect ((variant) => {
88 | info_box.switch_launcher (launchers.nth_data (variant.get_int32 ()).title, variant.get_int32 ());
89 | });
90 |
91 | return action;
92 | }
93 | }
94 | }
--------------------------------------------------------------------------------