├── .editorconfig ├── .github ├── CODEOWNERS ├── ISSUE_TEMPLATE │ ├── bug_report.yml │ ├── config.yml │ └── feature_request.yml ├── dependabot.yml ├── pull_request_template.md └── workflows │ ├── build.yml │ ├── dependency-review.yml │ ├── greetings.yml │ ├── pypi-dependencies.yml │ ├── pysa.yml │ ├── repo.yml │ ├── translation.yml │ └── typos.yml ├── .gitignore ├── .gitmodules ├── .pylintrc ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── HACKING.md ├── LICENSE ├── MAINTAINERS.md ├── Makefile ├── README.md ├── ROADMAP.md ├── SECURITY.md ├── build-aux └── flatpak │ ├── com.github.GradienceTeam.Gradience.Devel.json │ ├── com.github.GradienceTeam.Gradience.json │ └── pypi-dependencies.json ├── data ├── com.github.GradienceTeam.Gradience.appdata.xml.in.in ├── com.github.GradienceTeam.Gradience.desktop.in.in ├── com.github.GradienceTeam.Gradience.gschema.xml.in ├── gradience.gresource.xml ├── icons │ ├── hicolor │ │ ├── scalable │ │ │ └── apps │ │ │ │ ├── com.github.GradienceTeam.Gradience.Devel.svg │ │ │ │ └── com.github.GradienceTeam.Gradience.svg │ │ └── symbolic │ │ │ └── apps │ │ │ └── com.github.GradienceTeam.Gradience-symbolic.svg │ ├── meson.build │ └── scalable │ │ └── actions │ │ ├── adw-gtk3-warning-symbolic.svg │ │ ├── bug-symbolic.svg │ │ ├── checkmark-symbolic.svg │ │ ├── code-symbolic.svg │ │ ├── color-picker-symbolic.svg │ │ ├── document-edit-symbolic.svg │ │ ├── document-save-symbolic.svg │ │ ├── larger-brush-symbolic.svg │ │ ├── palette-symbolic.svg │ │ ├── settings-symbolic.svg │ │ ├── star-large-symbolic.svg │ │ └── star-outline-rounded-symbolic.svg ├── images │ └── welcome.svg ├── meson.build ├── presets │ ├── adwaita-dark.json │ ├── adwaita.json │ └── pretty-purple.json ├── shell │ ├── meson.build │ └── templates │ │ ├── 42 │ │ ├── check-box.template │ │ ├── colors.template │ │ ├── gnome-shell.template │ │ ├── palette.template │ │ ├── panel.template │ │ └── switches.template │ │ ├── 43 │ │ ├── check-box.template │ │ ├── colors.template │ │ ├── gnome-shell.template │ │ ├── palette.template │ │ ├── panel.template │ │ └── switches.template │ │ ├── 44 │ │ ├── check-box.template │ │ ├── colors.template │ │ ├── gnome-shell.template │ │ ├── palette.template │ │ ├── panel.template │ │ └── switches.template │ │ └── 45 │ │ ├── check-box.template │ │ ├── colors.template │ │ ├── gnome-shell.template │ │ ├── palette.template │ │ ├── panel.template │ │ └── switches.template ├── style.css └── ui │ ├── app_type_dialog.blp │ ├── builtin_preset_row.blp │ ├── custom_css_group.blp │ ├── error_list_row.blp │ ├── explore_preset_row.blp │ ├── help_overlay.blp │ ├── log_out_dialog.blp │ ├── meson.build │ ├── monet_theming_group.blp │ ├── no_plugin_window.blp │ ├── option_row.blp │ ├── palette_shades.blp │ ├── plugin_row.blp │ ├── preferences_window.blp │ ├── preset_row.blp │ ├── presets_manager_window.blp │ ├── repo_row.blp │ ├── reset_preset_group.blp │ ├── save_dialog.blp │ ├── share_window.blp │ ├── shell_prefs_window.blp │ ├── shell_theming_group.blp │ ├── theming_empty_group.blp │ ├── welcome_window.blp │ └── window.blp ├── gradience.doap ├── gradience ├── __init__.py ├── backend │ ├── __init__.py │ ├── constants.py.in │ ├── css_parser.py │ ├── exceptions.py │ ├── flatpak_overrides.py │ ├── globals.py │ ├── logger.py │ ├── meson.build │ ├── models │ │ ├── __init__.py │ │ ├── meson.build │ │ ├── preset.py │ │ └── repo.py │ ├── preset_downloader.py │ ├── struct.md │ ├── theming │ │ ├── __init__.py │ │ ├── meson.build │ │ ├── monet.py │ │ ├── preset.py │ │ └── shell.py │ └── utils │ │ ├── __init__.py │ │ ├── colors.py │ │ ├── common.py │ │ ├── gnome.py │ │ ├── gsettings.py │ │ ├── meson.build │ │ ├── networking.py │ │ ├── subprocess.py │ │ └── theming.py ├── frontend │ ├── __init__.py │ ├── cli │ │ ├── __init__.py │ │ ├── cli.in │ │ └── meson.build │ ├── dialogs │ │ ├── __init__.py │ │ ├── app_type_dialog.py │ │ ├── meson.build │ │ ├── save_dialog.py │ │ └── unsupported_shell_dialog.py │ ├── gradience.in │ ├── main.py │ ├── meson.build │ ├── schemas │ │ ├── __init__.py │ │ ├── meson.build │ │ ├── preset_schema.py │ │ └── shell_schema.py │ ├── struct.md │ ├── utils │ │ ├── __init__.py │ │ ├── actions.py │ │ ├── meson.build │ │ └── run_async.py │ ├── views │ │ ├── __init__.py │ │ ├── about_window.py │ │ ├── main_window.py │ │ ├── meson.build │ │ ├── no_plugin_window.py │ │ ├── plugins_list.py │ │ ├── preferences_window.py │ │ ├── presets_manager_window.py │ │ ├── share_window.py │ │ ├── shell_prefs_window.py │ │ └── welcome_window.py │ └── widgets │ │ ├── __init__.py │ │ ├── builtin_preset_row.py │ │ ├── custom_css_group.py │ │ ├── error_list_row.py │ │ ├── explore_preset_row.py │ │ ├── meson.build │ │ ├── monet_theming_group.py │ │ ├── option_row.py │ │ ├── palette_shades.py │ │ ├── plugin_row.py │ │ ├── preset_row.py │ │ ├── repo_row.py │ │ ├── reset_preset_group.py │ │ ├── shell_theming_group.py │ │ └── theming_empty_group.py └── meson.build ├── local.sh ├── local_cli.sh ├── meson.build ├── po ├── Gradience.pot ├── LINGUAS ├── POTFILES ├── ar.po ├── az.po ├── cs.po ├── de.po ├── es.po ├── eu.po ├── fi.po ├── fr.po ├── he.po ├── hi.po ├── hr.po ├── id.po ├── it.po ├── ko.po ├── meson.build ├── nl.po ├── oc.po ├── pl.po ├── pt.po ├── pt_BR.po ├── ro.po ├── ru.po ├── sr.po ├── sv.po ├── ta.po ├── tr.po ├── uk.po ├── update_linguas.py ├── update_potfile.sh └── zh_Hans.po ├── requirements.txt └── typos.toml /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | [*] 8 | end_of_line = lf 9 | charset = utf-8 10 | trim_trailing_whitespace = true 11 | insert_final_newline = true 12 | indent_style = space 13 | indent_size = 4 14 | 15 | [meson.build] 16 | indent_size = 2 17 | 18 | [*.md] 19 | trim_trailing_whitespace = false 20 | 21 | [*.blp] 22 | indent_size = 2 23 | 24 | [*.json] 25 | indent_size = 2 26 | 27 | [*.yml] 28 | indent_size = 2 29 | 30 | [*.xml*] 31 | indent_size = 2 32 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | @GradienceTeam/Core 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.yml: -------------------------------------------------------------------------------- 1 | name: 🐛 Bug Report 2 | description: File a bug report 3 | title: "bug: " 4 | labels: "type/bug" 5 | body: 6 | - type: markdown 7 | attributes: 8 | value: | 9 | Thank you for taking the time to fill out this bug report! 10 | 11 | - type: checkboxes 12 | attributes: 13 | label: Is there an existing issue for this? 14 | description: Please search to see if an issue already exists for your problem. 15 | options: 16 | - label: I have searched the existing issues 17 | required: true 18 | 19 | - type: textarea 20 | attributes: 21 | label: What happened? 22 | description: A clear and concise description of what the bug is. 23 | placeholder: "Tell us what you see!" 24 | value: "A bug happened!" 25 | validations: 26 | required: true 27 | 28 | - type: textarea 29 | attributes: 30 | label: To Reproduce 31 | description: Steps to reproduce the behavior. 32 | placeholder: | 33 | 1. Go to '…' 34 | 2. Click on '…' 35 | 3. Scroll down to '…' 36 | 4. See error 37 | validations: 38 | required: true 39 | 40 | - type: textarea 41 | attributes: 42 | label: Expected behavior 43 | description: A clear and concise description of what you expected to happen. 44 | 45 | - type: textarea 46 | attributes: 47 | label: Screenshots 48 | description: If applicable, add screenshots to help explain your problem. 49 | 50 | - type: markdown 51 | attributes: 52 | value: "## System" 53 | 54 | - type: input 55 | attributes: 56 | label: OS 57 | description: On which system do you run the app? 58 | placeholder: "Fedora Linux 36 (Workstation Edition)" 59 | validations: 60 | required: true 61 | 62 | - type: input 63 | attributes: 64 | label: DE/WM version 65 | description: Which version of desktop environment / window manager do you use? 66 | placeholder: "GNOME 42.3, i3wm 4.21" 67 | validations: 68 | required: true 69 | 70 | - type: input 71 | attributes: 72 | label: Version 73 | description: Which version of the Gradience do you use? 74 | placeholder: "0.3.0, 0.3.0-7e0386b, `main` branch" 75 | validations: 76 | required: true 77 | 78 | - type: dropdown 79 | attributes: 80 | label: Installation method 81 | description: How did you install Gradience ? 82 | options: 83 | - Flatpak from Flathub 84 | - Flatpak from Github Actions 85 | - Flatpak from manual build 86 | - AUR 87 | - Fedora COPR (lyessaadi/gradience) 88 | - Manual using meson 89 | - Other 90 | validations: 91 | required: true 92 | 93 | - type: textarea 94 | attributes: 95 | label: Enabled system extensions (GNOME specific) 96 | description: "Please paste here a list of enabled extensions, unless you know that this information won't be needed in your issue." 97 | placeholder: "Use `gnome-extensions list --enabled` command to get a list." 98 | 99 | - type: textarea 100 | attributes: 101 | label: Additional context 102 | description: Add any other context about the problem here. 103 | 104 | - type: checkboxes 105 | attributes: 106 | label: Code of Conduct 107 | description: By submitting this issue, you agree to follow our [Code of Conduct](https://github.com/GradienceTeam/Gradience/blob/main/CODE_OF_CONDUCT.md) 108 | options: 109 | - label: I agree to follow this project's Code of Conduct 110 | required: true 111 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: 🎨 Preset request 4 | url: https://github.com/GradienceTeam/Community/issues/new?assignees=&labels=enhancement%2Cpreset+request&template=preset_request.yml&title=feat%3A+ 5 | about: Request a port of a theme into Gradience 6 | - name: 🔌 Plug-in request 7 | url: https://github.com/GradienceTeam/Plugins/issues/new?assignees=&labels=enhancement%2Cplugin-request&template=plugin_request.yml&title=plug%3A+ 8 | about: Request a plugin for customizing an external application or tool 9 | - name: 🚀 GitHub Community 10 | url: https://github.com/orgs/GradienceTeam/discussions 11 | about: Please ask and answer questions here. 12 | - name: 📬 Matrix 13 | url: https://matrix.to/#/#Gradience:matrix.org 14 | about: Chat on matrix. 15 | - name: 🎁️ Share your presets 16 | url: https://GitHub.com/Gradienceteam/Community 17 | about: Share your presets and see them in the explore tab 18 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.yml: -------------------------------------------------------------------------------- 1 | name: "💡 Feature request" 2 | description: Suggest an idea for this project 3 | title: "feat: " 4 | labels: ["enhancement", "feature-request"] 5 | body: 6 | - type: markdown 7 | attributes: 8 | value: | 9 | Thanks for taking the time to contribute! Contributions are what make the open-source and the GNOME community such an amazing place to learn, and create. Any contributions you make will benefit everybody else and are greatly appreciated. 10 | - type: textarea 11 | id: description 12 | attributes: 13 | label: Feature description 14 | description: A clear and concise description of what the feature request is. Please include if your feature request is related to a problem 15 | validations: 16 | required: true 17 | - type: textarea 18 | id: additional 19 | attributes: 20 | label: Additional Context 21 | description: "List any other information that is relevant to your issue. Stack traces, related issues, suggestions on how to add, use case, Stack Overflow links, forum links, screenshots, OS if applicable, etc." 22 | validations: 23 | required: false 24 | - type: checkboxes 25 | attributes: 26 | label: Did you read the Code of Conduct? 27 | options: 28 | - label: I have read the [Code of Conduct](https://github.com/GradienceTeam/Gradience/blob/main/CODE_OF_CONDUCT.md). 29 | required: true 30 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "pip" # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "daily" 12 | - package-ecosystem: "github-actions" 13 | directory: "/" 14 | schedule: 15 | interval: "daily" 16 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ## Description 2 | 3 | 4 | 5 | Fixes #(issue) 6 | 7 | ## Type of change 8 | 9 | 10 | - [ ] Bugfix (Change which fixes an issue) 11 | - [ ] New feature (Change which adds new functionality) 12 | - [ ] Enhancement (Change which slightly improves existing code) 13 | - [ ] Breaking change (This change will introduce incompatibility with existing functionality) 14 | 15 | ## Changelog 16 | 17 | - Fixed … 18 | - Added … 19 | 20 | ## Testing 21 | 22 | - [ ] I have tested my changes and verified that they work as expected 23 | 24 | ### How to test the changes 25 | 26 | 27 | No information provided. 28 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | # Change the look of Adwaita, with ease 2 | # Copyright (C) 2022 Gradience Team 3 | # 4 | # This program is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | 17 | 18 | name: Build 19 | 20 | on: 21 | push: 22 | branches: [ "main" ] 23 | paths-ignore: 24 | - '**/*.md' 25 | pull_request: 26 | paths-ignore: 27 | - '**/*.md' 28 | 29 | jobs: 30 | flatpak: 31 | name: Flatpak 32 | runs-on: ubuntu-latest 33 | container: 34 | image: bilelmoussaoui/flatpak-github-actions:gnome-nightly 35 | options: --privileged 36 | strategy: 37 | matrix: 38 | arch: [x86_64, aarch64] 39 | # Don't fail the whole workflow if one architecture fails 40 | fail-fast: false 41 | steps: 42 | - name: Checkout 43 | uses: actions/checkout@v4 44 | 45 | with: 46 | submodules: recursive 47 | 48 | - name: Install dependencies 49 | run: | 50 | dnf -y install docker 51 | 52 | - name: Set up QEMU 53 | id: qemu 54 | uses: docker/setup-qemu-action@v3 55 | with: 56 | platforms: arm64 57 | 58 | - uses: flatpak/flatpak-github-actions/flatpak-builder@v6.3 59 | 60 | with: 61 | repository-name: gnome-nightly 62 | bundle: gradience-devel.flatpak 63 | manifest-path: build-aux/flatpak/com.github.GradienceTeam.Gradience.Devel.json 64 | cache-key: flatpak-builder-${{ github.sha }} 65 | arch: ${{ matrix.arch }} 66 | -------------------------------------------------------------------------------- /.github/workflows/dependency-review.yml: -------------------------------------------------------------------------------- 1 | # Dependency Review Action 2 | # 3 | # This Action will scan dependency manifest files that change as part of a Pull Request, surfacing known-vulnerable versions of the packages declared or updated in the PR. Once installed, if the workflow run is marked as required, PRs introducing known-vulnerable packages will be blocked from merging. 4 | # 5 | # Source repository: https://github.com/actions/dependency-review-action 6 | # Public documentation: https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/about-dependency-review#dependency-review-enforcement 7 | 8 | 9 | name: Dependency Review 10 | 11 | on: 12 | pull_request: 13 | 14 | permissions: 15 | contents: read 16 | 17 | jobs: 18 | dependency-review: 19 | runs-on: ubuntu-latest 20 | steps: 21 | - name: Checkout repository 22 | uses: actions/checkout@v4 23 | 24 | - name: Dependency Review 25 | uses: actions/dependency-review-action@v4 26 | -------------------------------------------------------------------------------- /.github/workflows/greetings.yml: -------------------------------------------------------------------------------- 1 | # Change the look of Adwaita, with ease 2 | # Copyright (C) 2022 Gradience Team 3 | # 4 | # This program is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | 17 | 18 | name: Greetings 19 | 20 | on: [pull_request_target, issues] 21 | 22 | jobs: 23 | greeting: 24 | runs-on: ubuntu-latest 25 | 26 | permissions: 27 | issues: write 28 | pull-requests: write 29 | steps: 30 | - uses: actions/first-interaction@v1 31 | with: 32 | repo-token: ${{ secrets.GITHUB_TOKEN }} 33 | issue-message: "Welcome on Gradience. 🥳 We really appreciate your contribution. The core team will review your issue as soon as possible. You can also join the Matrix room: https://matrix.to/#/#Gradience-space:envs.net or the Discord server: https://discord.com/invite/4njFDtfGEZ" 34 | pr-message: "Welcome on Gradience. 🥳 We really appreciate your contribution. The core team will review your pull request as soon as possible. You can also join the Matrix room: https://matrix.to/#/#Gradience-space:envs.net or the Discord server: https://discord.com/invite/4njFDtfGEZ." 35 | -------------------------------------------------------------------------------- /.github/workflows/pypi-dependencies.yml: -------------------------------------------------------------------------------- 1 | # Change the look of Adwaita, with ease 2 | # Copyright (C) 2022 Gradience Team 3 | # 4 | # This program is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | 17 | 18 | name: Generate PyPI Dependencies 19 | 20 | on: 21 | push: 22 | branches: [ "main" ] 23 | paths: requirements.txt 24 | workflow_dispatch: 25 | 26 | jobs: 27 | build: 28 | runs-on: ubuntu-latest 29 | steps: 30 | - uses: actions/checkout@v4 31 | - uses: actions/setup-python@v5.1.0 32 | with: 33 | python-version: '3.10' 34 | 35 | - name: Run a multi-line script 36 | run: | 37 | curl -O https://raw.githubusercontent.com/flatpak/flatpak-builder-tools/master/pip/flatpak-pip-generator 38 | chmod +x flatpak-pip-generator 39 | python -m pip install requirements-parser 40 | ./flatpak-pip-generator --requirements-file=requirements.txt --output pypi-dependencies 41 | mv pypi-dependencies.json build-aux/flatpak/pypi-dependencies.json 42 | 43 | - name: Create pull request 44 | uses: peter-evans/create-pull-request@v6.0.5 45 | with: 46 | author: "AdwCustomizer " 47 | title: "meta: update PyPI dependencies for Flatpak" 48 | body: "This automated PR contains an auto-generated `pypi-dependencies.json` file used in Flatpak manifests." 49 | labels: flatpak, ci/automated-pr 50 | commit-message: "meta: update Flatpak PyPI dependencies" 51 | committer: "AdwCustomizer " 52 | branch: update-pypi-deps 53 | -------------------------------------------------------------------------------- /.github/workflows/pysa.yml: -------------------------------------------------------------------------------- 1 | # This workflow uses actions that are not certified by GitHub. 2 | # They are provided by a third-party and are governed by 3 | # separate terms of service, privacy policy, and support 4 | # documentation. 5 | 6 | # This workflow integrates Python Static Analyzer (Pysa) with 7 | # GitHub's Code Scanning feature. 8 | # 9 | # Python Static Analyzer (Pysa) is a security-focused static 10 | # analysis tool that tracks flows of data from where they 11 | # originate to where they terminate in a dangerous location. 12 | # 13 | # See https://pyre-check.org/docs/pysa-basics/ 14 | 15 | 16 | name: Pysa 17 | 18 | on: 19 | workflow_dispatch: 20 | push: 21 | branches: [ "main" ] 22 | pull_request: 23 | branches: [ "main" ] 24 | schedule: 25 | - cron: '34 17 * * 1' 26 | 27 | permissions: 28 | contents: read 29 | 30 | jobs: 31 | pysa: 32 | permissions: 33 | actions: read 34 | contents: read 35 | security-events: write 36 | 37 | runs-on: ubuntu-latest 38 | steps: 39 | - uses: actions/checkout@v4 40 | with: 41 | submodules: true 42 | 43 | - name: Run Pysa 44 | uses: facebook/pysa-action@f46a63777e59268613bd6e2ff4e29f144ca9e88b 45 | with: 46 | # To customize these inputs: 47 | # See https://github.com/facebook/pysa-action#inputs 48 | repo-directory: './' 49 | requirements-path: 'requirements.txt' 50 | infer-types: true 51 | include-default-sapp-filters: true 52 | -------------------------------------------------------------------------------- /.github/workflows/repo.yml: -------------------------------------------------------------------------------- 1 | name: Repo 2 | 3 | on: 4 | # Rebuild once a day 5 | #schedule: 6 | # - cron: "0 0 * * *" 7 | push: 8 | workflow_dispatch: 9 | 10 | jobs: 11 | flatter: 12 | name: Flatter 13 | runs-on: ubuntu-latest 14 | container: 15 | image: ghcr.io/andyholmes/flatter/gnome:master 16 | options: --privileged 17 | 18 | strategy: 19 | matrix: 20 | arch: [x86_64, aarch64] 21 | fail-fast: false 22 | # Only one job at a time can use the shared repository cache 23 | max-parallel: 1 24 | 25 | steps: 26 | # Checkout a repository with Flatpak manifests 27 | - name: Checkout 28 | uses: actions/checkout@v4 29 | with: 30 | submodules: recursive 31 | 32 | # See "Multiple Architectures" below 33 | - name: Setup QEMU 34 | if: ${{ matrix.arch == 'aarch64' }} 35 | id: qemu 36 | uses: docker/setup-qemu-action@v3 37 | with: 38 | platforms: arm64 39 | 40 | # See "GPG Signing" below 41 | - name: Setup GPG 42 | id: gpg 43 | uses: crazy-max/ghaction-import-gpg@v6 44 | with: 45 | gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }} 46 | passphrase: ${{ secrets.GPG_PASSPHRASE }} 47 | 48 | - name: Build 49 | uses: andyholmes/flatter@main 50 | with: 51 | files: | 52 | build-aux/flatpak/com.github.GradienceTeam.Gradience.Devel.json 53 | arch: ${{ matrix.arch }} 54 | gpg-sign: ${{ steps.gpg.outputs.fingerprint }} 55 | upload-bundles: true 56 | upload-pages-artifact: true 57 | upload-pages-includes: | 58 | repo/default.css 59 | repo/index.html 60 | 61 | # See "Github Pages" below 62 | deploy: 63 | name: Deploy 64 | runs-on: ubuntu-latest 65 | needs: flatter 66 | permissions: 67 | pages: write 68 | id-token: write 69 | environment: 70 | name: github-pages 71 | url: ${{ steps.deployment.outputs.page_url }} 72 | 73 | steps: 74 | - name: GitHub Pages 75 | id: deployment 76 | uses: actions/deploy-pages@v4 77 | -------------------------------------------------------------------------------- /.github/workflows/translation.yml: -------------------------------------------------------------------------------- 1 | # Change the look of Adwaita, with ease 2 | # Copyright (C) 2022 Gradience Team 3 | # 4 | # This program is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | 17 | 18 | name: "Translation" 19 | 20 | on: 21 | workflow_dispatch: 22 | 23 | jobs: 24 | generate: 25 | name: Generate .pot and LINGUAS 26 | runs-on: ubuntu-latest 27 | 28 | steps: 29 | - name: Checkout repository 30 | uses: actions/checkout@v4 31 | 32 | - name: Update .pot 33 | uses: GradienceTeam/action-update-pot@main 34 | with: 35 | title: "Gradience POT file" 36 | copyright: "Gradience Team" 37 | license: "GNU GPLv3" 38 | author: "Gradience Team" 39 | commiter: "Gradience Bot" 40 | commiter_email: "AdwCustomizerTeam@proton.me" 41 | env: 42 | GITHUB_TOKEN: ${{ secrets.ACCESS_TOKEN }} 43 | -------------------------------------------------------------------------------- /.github/workflows/typos.yml: -------------------------------------------------------------------------------- 1 | # Change the look of Adwaita, with ease 2 | # Copyright (C) 2022 Gradience Team 3 | # 4 | # This program is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | 17 | 18 | name: Typos 19 | 20 | on: 21 | pull_request: 22 | schedule: 23 | - cron: '0 0,12 * * *' 24 | workflow_dispatch: 25 | 26 | jobs: 27 | typos: 28 | name: Typos 29 | runs-on: ubuntu-latest 30 | steps: 31 | - uses: actions/checkout@v4 32 | 33 | - name: Check for typos 34 | uses: crate-ci/typos@v1.22.7 35 | with: 36 | config: typos.toml 37 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "data/submodules"] 2 | path = data/submodules 3 | url = https://github.com/GradienceTeam/Submodules -------------------------------------------------------------------------------- /.pylintrc: -------------------------------------------------------------------------------- 1 | [MAIN] 2 | 3 | # Use multiple processes to speed up Pylint. 4 | jobs=4 5 | 6 | 7 | [MESSAGES CONTROL] 8 | 9 | # Disable the message, report, category or checker with the given id(s). You 10 | # can either give multiple identifiers separated by comma (,) or put this 11 | # option multiple times (only on the command line, not in the configuration 12 | # file where it should appear only once). You can also use "--disable=all" to 13 | # disable everything first and then re-enable specific checks. For example, if 14 | # you want to run only the similarities checker, you can use "--disable=all 15 | # --enable=similarities". If you want to run only the classes checker, but have 16 | # no Warning level messages displayed, use "--disable=all --enable=classes 17 | # --disable=W". 18 | disable=locally-disabled, 19 | suppressed-message, 20 | useless-suppression, 21 | #line-too-long, 22 | fixme, 23 | missing-module-docstring, 24 | missing-function-docstring, 25 | missing-class-docstring, 26 | invalid-name, 27 | no-member, 28 | too-few-public-methods, 29 | attribute-defined-outside-init, 30 | logging-fstring-interpolation, 31 | unused-argument 32 | 33 | 34 | [FORMAT] 35 | 36 | # String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 37 | # tab). 38 | indent-string=' ' 39 | 40 | # Number of spaces of indent required inside a hanging or continued line. 41 | indent-after-paren=4 42 | 43 | # Expected format of line ending, e.g. empty (any line ending), LF or CRLF. 44 | expected-line-ending-format=LF 45 | 46 | 47 | [MISCELLANEOUS] 48 | 49 | # List of note tags to take in consideration, separated by a comma. 50 | notes=FIXME,XXX,TODO 51 | 52 | 53 | [VARIABLES] 54 | 55 | # Tells whether we should check for unused import in __init__ files. 56 | init-import=no 57 | 58 | # A regular expression matching the name of dummy variables (i.e. expectedly 59 | # not used). 60 | dummy-variables-rgx=(_+[a-zA-Z0-9]*?$)|dummy 61 | 62 | # List of additional names supposed to be defined in builtins. Remember that 63 | # you should avoid to define new builtins when possible. 64 | additional-builtins=_ 65 | 66 | 67 | [SIMILARITIES] 68 | 69 | # Minimum lines number of a similarity. 70 | min-similarity-lines=4 71 | 72 | # Ignore comments when computing similarities. 73 | ignore-comments=yes 74 | 75 | # Ignore docstrings when computing similarities. 76 | ignore-docstrings=yes 77 | 78 | # Ignore imports when computing similarities. 79 | ignore-imports=no 80 | -------------------------------------------------------------------------------- /HACKING.md: -------------------------------------------------------------------------------- 1 | ## 🙌 Contribute to Gradience 2 | 3 | ### Code 4 | 5 | Fork this repository, then create a push request when you're done adding features or fixing bugs. 6 | 7 | ### Localization 8 | 9 | You can help Gradience translate into your native language. If you found any typos 10 | or think you can improve a translation, you can use the [Weblate](https://hosted.weblate.org/engage/GradienceTeam) platform. 11 | 12 | [![Translation status](https://hosted.weblate.org/widgets/GradienceTeam/-/multi-auto.svg)](https://hosted.weblate.org/engage/GradienceTeam) 13 | 14 | 15 | ## 🏗️ Building from source 16 | 17 | ### GNOME Builder 18 | 19 | GNOME Builder is the environment used for developing this application. 20 | It can use Flatpak manifests to create a consistent building and running 21 | environment cross-distro. Thus, it is highly recommended you use it. 22 | 23 | 1. Download [GNOME Builder](https://flathub.org/apps/details/org.gnome.Builder). 24 | 2. In Builder, click the "Clone Repository" button at the bottom, using `https://github.com/GradienceTeam/Gradience.git` as the URL. 25 | 3. Click the build button at the top once the project is loaded. 26 | 27 | ### Flatpak Builder 28 | 29 | `flatpak-builder` is a wrapper around the `flatpak build` command that automates the building of applications and their dependencies. 30 | It uses Flatpak manifests to download and pack needed dependencies with compiled program into a single Flatpak image that can be later distributed or installed on your system. We recommend this method if you have problems with GNOME Builder. 31 | 32 | #### Prerequisites 33 | 34 | - Flatpak Builder `flatpak-builder` 35 | - GNOME SDK runtime `org.gnome.Sdk//44` 36 | - GNOME Platform runtime `org.gnome.Platform//44` 37 | 38 | Install required runtimes: 39 | ```shell 40 | flatpak install org.gnome.Sdk//44 org.gnome.Platform//44 41 | ``` 42 | 43 | #### Build Instruction 44 | 45 | ##### User installation 46 | ```shell 47 | git clone https://github.com/GradienceTeam/Gradience.git 48 | cd Gradience 49 | git submodule update --init --recursive 50 | flatpak-builder --install --user --force-clean repo/ build-aux/flatpak/com.github.GradienceTeam.Gradience.json 51 | ``` 52 | 53 | ##### System installation 54 | ```shell 55 | git clone https://github.com/GradienceTeam/Gradience.git 56 | cd Gradience 57 | git submodule update --init --recursive 58 | flatpak-builder --install --system --force-clean repo/ build-aux/flatpak/com.github.GradienceTeam.Gradience.json 59 | ``` 60 | 61 | ### Meson 62 | 63 | #### Prerequisites 64 | 65 | The following packages are required to build Gradience: 66 | 67 | - Python 3 `python` 68 | - PyGObject `python-gobject` 69 | - Blueprint [`blueprint-compiler`](https://jwestman.pages.gitlab.gnome.org/blueprint-compiler/setup.html) 70 | - GTK 4 `gtk4` 71 | - Libadwaita (>= 1.2.alpha) `libadwaita` 72 | - Libsoup 3 (>= 3.2.0) `libsoup` 73 | - Meson `meson` 74 | - Ninja `ninja-build` 75 | 76 | Required Python libraries: 77 | 78 | ```shell 79 | pip install -r requirements.txt 80 | ``` 81 | 82 | #### Build Instruction 83 | 84 | ##### Global installation 85 | 86 | ```shell 87 | git clone https://github.com/GradienceTeam/Gradience.git 88 | cd Gradience 89 | git submodule update --init --recursive 90 | meson setup builddir 91 | meson configure builddir -Dprefix=/usr/local 92 | sudo ninja -C builddir install 93 | ``` 94 | 95 | ##### Local build (for testing and development purposes) 96 | 97 | ```shell 98 | git clone https://github.com/GradienceTeam/Gradience.git 99 | cd Gradience 100 | git submodule update --init --recursive 101 | meson setup builddir 102 | meson configure builddir -Dprefix="$(pwd)/builddir" 103 | ninja -C builddir install 104 | ninja -C builddir run 105 | ``` 106 | 107 | > **Note** 108 | > During testing and development, as a convenience, you can use the `local.sh` script to quickly rebuild local builds. 109 | > If you want to use CLI in local builds, you should type: `./local_cli.sh ` instead of `gradience-cli`. 110 | 111 | -------------------------------------------------------------------------------- /MAINTAINERS.md: -------------------------------------------------------------------------------- 1 | # Maintainers 2 | 3 | This application was created by [@ArtyIF](https://github.com/ArtyIF). Now it's maintained by the Gradience Team. 4 | 5 | ## Gradience Team 6 | 7 | - [@0xMRTT](https://github.com/0xMRTT) as main developer 8 | - [@daudix-UFO](https://github.com/daudix-UFO) as designer 9 | - [@LyesSaadi](https://github.com/LyesSaadi) as packager 10 | - [@tfuxu](https://github.com/tfuxu) as developer 11 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | install: 2 | sudo meson setup builddir --prefix=/usr/local --wipe 3 | sudo ninja -C builddir install 4 | 5 | global: 6 | sudo meson setup builddir --prefix=/usr --wipe 7 | sudo ninja -C builddir install 8 | 9 | release: 10 | sudo meson setup builddir --prefix=/usr --Dbuildtype=release --wipe 11 | sudo ninja -C builddir install 12 | 13 | user: 14 | meson setup builddir --prefix="$(shell pwd)/builddir" --buildtype=debug --wipe 15 | ninja -C builddir install 16 | ninja -C builddir run 17 | -------------------------------------------------------------------------------- /ROADMAP.md: -------------------------------------------------------------------------------- 1 | ## 🛣️ Roadmap 2 | 3 | Gradience is completely usable, if you like to see a new feature, open an issue or submit a PR 4 | 5 | ### Base features 6 | 7 | - [x] Customize named colors, either with a color picker or with text 8 | - [x] Explanations for some named colors 9 | - [x] Partial theme preview 10 | - [x] Built-in presets for Adwaita and Adwaita Dark (based on default Libadwaita colors) 11 | - [x] Apply changes to Libadwaita, GTK 4 (with extracted Libadwaita theme) and GTK 3 (with the adw-gtk3 theme) applications 12 | - [x] Load and create custom presets 13 | - [x] View adw-gtk3's support of variables 14 | - [x] View parsing errors 15 | - [x] Customize palette colors 16 | - [x] Add custom CSS code 17 | - [x] Localization support 18 | - [x] Normalize color variables 19 | - [x] Make the code more secure 20 | - [x] Add preset manager with option to download other users presets 21 | - [x] Release on Flathub 22 | - [x] Add autoload theme from CSS 23 | - [ ] Make UX more foolproof (bruh) 24 | - [ ] Add ability to create light/dark presets **(High priority)** 25 | - [ ] Add a full theme preview instead of GTK 4 Demo 26 | - [ ] Add ability to generate preset from one color 27 | 28 | ### Plugins 29 | 30 | - [x] Add plugin support. Will help integration with others tools. 31 | - [x] Customize Firefox GNOME theme 32 | - [x] Customize GNOME Shell **(High priority)** 33 | - [x] Customize GDM **(High priority)** 34 | - [ ] Customize KvLibadwaita 35 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | ## 🔒️ Security Policy 2 | 3 | ### Supported Versions 4 | 5 | Only two latest versions are officially supported, but older versions get some help too. 6 | 7 | | Version | Supported | 8 | | ------- | ------------------ | 9 | | 0.4.x | :white_check_mark: | 10 | | 0.3.x | :white_check_mark: | 11 | | < 0.2 | :x: | 12 | 13 | ### Reporting a Vulnerability 14 | 15 | Normally Gradience can't have security issues, but if you have found a vulnerability, please don't submit a public issue. 16 | 17 | Instead, report this vulnerability to [AdwCustomizerTeam@proton.me](mailto:AdwCustomizerTeam@proton.me) and include as much details as possible. 18 | -------------------------------------------------------------------------------- /data/com.github.GradienceTeam.Gradience.desktop.in.in: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Name=Gradience 3 | Exec=gradience 4 | Icon=@APP_ID@ 5 | Terminal=false 6 | Type=Application 7 | Categories=GTK;Utility; 8 | Keywords=AdwCustomizer;Adwaita Manager;GNOME;Customization; 9 | StartupNotify=true 10 | -------------------------------------------------------------------------------- /data/com.github.GradienceTeam.Gradience.gschema.xml.in: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 1000 6 | 7 | 8 | 700 9 | 10 | 11 | false 12 | 13 | 14 | false 15 | 16 | 17 | true 18 | 19 | 20 | '0.2.2' 21 | 22 | 23 | [] 24 | 25 | 26 | ['shell', 'monet'] 27 | 28 | 29 | false 30 | 31 | 32 | false 33 | 34 | 35 | false 36 | 37 | 38 | false 39 | 40 | 41 | {} 42 | 43 | 44 | {} 45 | 46 | 47 | [] 48 | 49 | 50 | false 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /data/gradience.gresource.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | presets/adwaita.json 5 | presets/adwaita-dark.json 6 | presets/pretty-purple.json 7 | ui/app_type_dialog.ui 8 | ui/builtin_preset_row.ui 9 | ui/custom_css_group.ui 10 | ui/error_list_row.ui 11 | ui/explore_preset_row.ui 12 | ui/monet_theming_group.ui 13 | ui/no_plugin_window.ui 14 | ui/option_row.ui 15 | ui/palette_shades.ui 16 | ui/plugin_row.ui 17 | ui/preferences_window.ui 18 | ui/preset_row.ui 19 | ui/presets_manager_window.ui 20 | ui/repo_row.ui 21 | ui/reset_preset_group.ui 22 | ui/save_dialog.ui 23 | ui/share_window.ui 24 | ui/shell_prefs_window.ui 25 | ui/shell_theming_group.ui 26 | ui/theming_empty_group.ui 27 | ui/welcome_window.ui 28 | ui/window.ui 29 | ui/help_overlay.ui 30 | 31 | images/welcome.svg 32 | style.css 33 | 34 | 35 | icons/scalable/actions/adw-gtk3-warning-symbolic.svg 36 | icons/scalable/actions/bug-symbolic.svg 37 | icons/scalable/actions/checkmark-symbolic.svg 38 | icons/scalable/actions/code-symbolic.svg 39 | icons/scalable/actions/color-picker-symbolic.svg 40 | icons/scalable/actions/document-edit-symbolic.svg 41 | icons/scalable/actions/document-save-symbolic.svg 42 | icons/scalable/actions/larger-brush-symbolic.svg 43 | icons/scalable/actions/palette-symbolic.svg 44 | icons/scalable/actions/settings-symbolic.svg 45 | icons/scalable/actions/star-large-symbolic.svg 46 | icons/scalable/actions/star-outline-rounded-symbolic.svg 47 | 48 | 49 | -------------------------------------------------------------------------------- /data/icons/hicolor/symbolic/apps/com.github.GradienceTeam.Gradience-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /data/icons/meson.build: -------------------------------------------------------------------------------- 1 | scalable_dir = join_paths('hicolor', 'scalable', 'apps') 2 | install_data( 3 | join_paths(scalable_dir, ('@0@.svg').format(APPLICATION_ID)), 4 | install_dir: join_paths(get_option('datadir'), 'icons', scalable_dir) 5 | ) 6 | 7 | symbolic_dir = join_paths('hicolor', 'symbolic', 'apps') 8 | install_data( 9 | join_paths(symbolic_dir, ('@0@-symbolic.svg').format(PROJECT_RDNN_NAME)), 10 | install_dir: join_paths(get_option('datadir'), 'icons', symbolic_dir), 11 | rename: '@0@-symbolic.svg'.format(APPLICATION_ID) 12 | ) 13 | -------------------------------------------------------------------------------- /data/icons/scalable/actions/adw-gtk3-warning-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /data/icons/scalable/actions/bug-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /data/icons/scalable/actions/checkmark-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /data/icons/scalable/actions/code-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /data/icons/scalable/actions/color-picker-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /data/icons/scalable/actions/document-edit-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /data/icons/scalable/actions/document-save-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /data/icons/scalable/actions/larger-brush-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /data/icons/scalable/actions/palette-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /data/icons/scalable/actions/settings-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /data/icons/scalable/actions/star-large-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /data/icons/scalable/actions/star-outline-rounded-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /data/meson.build: -------------------------------------------------------------------------------- 1 | gnome = import('gnome') 2 | 3 | subdir('ui') 4 | 5 | desktop_file = i18n.merge_file( 6 | input: configure_file( 7 | input: '@0@.desktop.in.in'.format(PROJECT_RDNN_NAME), 8 | output: '@BASENAME@', 9 | configuration: conf 10 | ), 11 | output: '@0@.desktop'.format(APPLICATION_ID), 12 | type: 'desktop', 13 | po_dir: '../po', 14 | install: true, 15 | install_dir: join_paths(get_option('datadir'), 'applications') 16 | ) 17 | 18 | desktop_utils = find_program('desktop-file-validate', required: false) 19 | if desktop_utils.found() 20 | test('Validate desktop file', desktop_utils, 21 | args: [desktop_file.full_path()] 22 | ) 23 | endif 24 | 25 | gnome.compile_resources('gradience', 26 | 'gradience.gresource.xml', 27 | gresource_bundle: true, 28 | source_dir: meson.current_build_dir(), 29 | install: true, 30 | install_dir: PKGDATA_DIR, 31 | dependencies: blueprints 32 | ) 33 | 34 | appstream_file = i18n.merge_file( 35 | input: configure_file( 36 | input: '@0@.appdata.xml.in.in'.format(PROJECT_RDNN_NAME), 37 | output: '@BASENAME@', 38 | configuration: configuration_data({ 39 | 'APP_ID': APPLICATION_ID, 40 | 'PROJECT_URL': PROJECT_URL, 41 | 'BUGTRACKER_URL': BUGTRACKER_URL, 42 | 'HELP_URL': HELP_URL, 43 | 'TRANSLATE_URL': TRANSLATE_URL 44 | }) 45 | ), 46 | output: '@0@.appdata.xml'.format(APPLICATION_ID), 47 | po_dir: '../po', 48 | install: true, 49 | install_dir: join_paths(get_option('datadir'), 'appdata') 50 | ) 51 | 52 | appstream_util = find_program('appstream-util', required: false) 53 | if appstream_util.found() 54 | test('Validate appstream file', appstream_util, 55 | args: ['validate', appstream_file.full_path()] 56 | ) 57 | endif 58 | 59 | configure_file( 60 | input: '@0@.gschema.xml.in'.format(PROJECT_RDNN_NAME), 61 | output: '@0@.gschema.xml'.format(APPLICATION_ID), 62 | configuration: conf, 63 | install: true, 64 | install_dir: join_paths(get_option('datadir'), 'glib-2.0/schemas') 65 | ) 66 | 67 | compile_schemas = find_program('glib-compile-schemas', required: false) 68 | if compile_schemas.found() 69 | test('Validate schema file', compile_schemas, 70 | args: ['--strict', '--dry-run', meson.current_source_dir()] 71 | ) 72 | endif 73 | 74 | subdir('icons') 75 | subdir('shell') 76 | subdir('submodules') -------------------------------------------------------------------------------- /data/presets/adwaita-dark.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Adwaita Dark", 3 | "variables": { 4 | "accent_color": "#78aeed", 5 | "accent_bg_color": "#3584e4", 6 | "accent_fg_color": "#ffffff", 7 | "destructive_color": "#ff7b63", 8 | "destructive_bg_color": "#c01c28", 9 | "destructive_fg_color": "#ffffff", 10 | "success_color": "#8ff0a4", 11 | "success_bg_color": "#26a269", 12 | "success_fg_color": "#ffffff", 13 | "warning_color": "#f8e45c", 14 | "warning_bg_color": "#cd9309", 15 | "warning_fg_color": "rgba(0, 0, 0, 0.8)", 16 | "error_color": "#ff7b63", 17 | "error_bg_color": "#c01c28", 18 | "error_fg_color": "#ffffff", 19 | "window_bg_color": "#242424", 20 | "window_fg_color": "#ffffff", 21 | "view_bg_color": "#1e1e1e", 22 | "view_fg_color": "#ffffff", 23 | "headerbar_bg_color": "#303030", 24 | "headerbar_fg_color": "#ffffff", 25 | "headerbar_border_color": "#ffffff", 26 | "headerbar_backdrop_color": "@window_bg_color", 27 | "headerbar_shade_color": "rgba(0, 0, 0, 0.36)", 28 | "headerbar_darker_shade_color": "rgba(0, 0, 0, 0.9)", 29 | "card_bg_color": "rgba(255, 255, 255, 0.08)", 30 | "card_fg_color": "#ffffff", 31 | "card_shade_color": "rgba(0, 0, 0, 0.36)", 32 | "dialog_bg_color": "#383838", 33 | "dialog_fg_color": "#ffffff", 34 | "popover_bg_color": "#383838", 35 | "popover_fg_color": "#ffffff", 36 | "popover_shade_color": "rgba(0, 0, 0, 0.36)", 37 | "shade_color": "rgba(0, 0, 0, 0.36)", 38 | "scrollbar_outline_color": "rgba(0, 0, 0, 0.5)", 39 | "thumbnail_bg_color": "#383838", 40 | "thumbnail_fg_color": "#ffffff", 41 | "sidebar_bg_color": "#303030", 42 | "sidebar_fg_color": "#ffffff", 43 | "sidebar_backdrop_color": "#2a2a2a", 44 | "sidebar_shade_color": "rgba(0, 0, 0, 0.36)", 45 | "secondary_sidebar_bg_color": "#2a2a2a", 46 | "secondary_sidebar_fg_color": "#ffffff", 47 | "secondary_sidebar_backdrop_color": "#272727", 48 | "secondary_sidebar_shade_color": "rgba(0, 0, 0, 0.36)" 49 | }, 50 | "palette": { 51 | "blue_": { 52 | "1": "#99c1f1", 53 | "2": "#62a0ea", 54 | "3": "#3584e4", 55 | "4": "#1c71d8", 56 | "5": "#1a5fb4" 57 | }, 58 | "green_": { 59 | "1": "#8ff0a4", 60 | "2": "#57e389", 61 | "3": "#33d17a", 62 | "4": "#2ec27e", 63 | "5": "#26a269" 64 | }, 65 | "yellow_": { 66 | "1": "#f9f06b", 67 | "2": "#f8e45c", 68 | "3": "#f6d32d", 69 | "4": "#f5c211", 70 | "5": "#e5a50a" 71 | }, 72 | "orange_": { 73 | "1": "#ffbe6f", 74 | "2": "#ffa348", 75 | "3": "#ff7800", 76 | "4": "#e66100", 77 | "5": "#c64600" 78 | }, 79 | "red_": { 80 | "1": "#f66151", 81 | "2": "#ed333b", 82 | "3": "#e01b24", 83 | "4": "#c01c28", 84 | "5": "#a51d2d" 85 | }, 86 | "purple_": { 87 | "1": "#dc8add", 88 | "2": "#c061cb", 89 | "3": "#9141ac", 90 | "4": "#813d9c", 91 | "5": "#613583" 92 | }, 93 | "brown_": { 94 | "1": "#cdab8f", 95 | "2": "#b5835a", 96 | "3": "#986a44", 97 | "4": "#865e3c", 98 | "5": "#63452c" 99 | }, 100 | "light_": { 101 | "1": "#ffffff", 102 | "2": "#f6f5f4", 103 | "3": "#deddda", 104 | "4": "#c0bfbc", 105 | "5": "#9a9996" 106 | }, 107 | "dark_": { 108 | "1": "#77767b", 109 | "2": "#5e5c64", 110 | "3": "#3d3846", 111 | "4": "#241f31", 112 | "5": "#000000" 113 | } 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /data/presets/adwaita.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Adwaita", 3 | "variables": { 4 | "accent_color": "#1c71d8", 5 | "accent_bg_color": "#3584e4", 6 | "accent_fg_color": "#ffffff", 7 | "destructive_color": "#c01c28", 8 | "destructive_bg_color": "#e01b24", 9 | "destructive_fg_color": "#ffffff", 10 | "success_color": "#26a269", 11 | "success_bg_color": "#2ec27e", 12 | "success_fg_color": "#ffffff", 13 | "warning_color": "#ae7b03", 14 | "warning_bg_color": "#e5a50a", 15 | "warning_fg_color": "rgba(0, 0, 0, 0.8)", 16 | "error_color": "#c01c28", 17 | "error_bg_color": "#e01b24", 18 | "error_fg_color": "#ffffff", 19 | "window_bg_color": "#fafafa", 20 | "window_fg_color": "rgba(0, 0, 0, 0.8)", 21 | "view_bg_color": "#ffffff", 22 | "view_fg_color": "rgba(0, 0, 0, 0.8)", 23 | "headerbar_bg_color": "#ebebeb", 24 | "headerbar_fg_color": "rgba(0, 0, 0, 0.8)", 25 | "headerbar_border_color": "rgba(0, 0, 0, 0.8)", 26 | "headerbar_backdrop_color": "@window_bg_color", 27 | "headerbar_shade_color": "rgba(0, 0, 0, 0.07)", 28 | "headerbar_darker_shade_color": "rgba(0, 0, 0, 0.12)", 29 | "card_bg_color": "#ffffff", 30 | "card_fg_color": "rgba(0, 0, 0, 0.8)", 31 | "card_shade_color": "rgba(0, 0, 0, 0.07)", 32 | "dialog_bg_color": "#fafafa", 33 | "dialog_fg_color": "rgba(0, 0, 0, 0.8)", 34 | "popover_bg_color": "#ffffff", 35 | "popover_fg_color": "rgba(0, 0, 0, 0.8)", 36 | "popover_shade_color": "rgba(0, 0, 0, 0.07)", 37 | "shade_color": "rgba(0, 0, 0, 0.07)", 38 | "scrollbar_outline_color": "#ffffff", 39 | "thumbnail_bg_color": "#ffffff", 40 | "thumbnail_fg_color": "rgba(0, 0, 0, 0.8)", 41 | "sidebar_bg_color": "#ebebeb", 42 | "sidebar_fg_color": "rgba(0, 0, 0, 0.8)", 43 | "sidebar_backdrop_color": "#f2f2f2", 44 | "sidebar_shade_color": "rgba(0, 0, 0, 0.07)", 45 | "secondary_sidebar_bg_color": "#f3f3f3", 46 | "secondary_sidebar_fg_color": "rgba(0, 0, 0, 0.8)", 47 | "secondary_sidebar_backdrop_color": "#f6f6f6", 48 | "secondary_sidebar_shade_color": "rgba(0, 0, 0, 0.07)" 49 | }, 50 | "palette": { 51 | "blue_": { 52 | "1": "#99c1f1", 53 | "2": "#62a0ea", 54 | "3": "#3584e4", 55 | "4": "#1c71d8", 56 | "5": "#1a5fb4" 57 | }, 58 | "green_": { 59 | "1": "#8ff0a4", 60 | "2": "#57e389", 61 | "3": "#33d17a", 62 | "4": "#2ec27e", 63 | "5": "#26a269" 64 | }, 65 | "yellow_": { 66 | "1": "#f9f06b", 67 | "2": "#f8e45c", 68 | "3": "#f6d32d", 69 | "4": "#f5c211", 70 | "5": "#e5a50a" 71 | }, 72 | "orange_": { 73 | "1": "#ffbe6f", 74 | "2": "#ffa348", 75 | "3": "#ff7800", 76 | "4": "#e66100", 77 | "5": "#c64600" 78 | }, 79 | "red_": { 80 | "1": "#f66151", 81 | "2": "#ed333b", 82 | "3": "#e01b24", 83 | "4": "#c01c28", 84 | "5": "#a51d2d" 85 | }, 86 | "purple_": { 87 | "1": "#dc8add", 88 | "2": "#c061cb", 89 | "3": "#9141ac", 90 | "4": "#813d9c", 91 | "5": "#613583" 92 | }, 93 | "brown_": { 94 | "1": "#cdab8f", 95 | "2": "#b5835a", 96 | "3": "#986a44", 97 | "4": "#865e3c", 98 | "5": "#63452c" 99 | }, 100 | "light_": { 101 | "1": "#ffffff", 102 | "2": "#f6f5f4", 103 | "3": "#deddda", 104 | "4": "#c0bfbc", 105 | "5": "#9a9996" 106 | }, 107 | "dark_": { 108 | "1": "#77767b", 109 | "2": "#5e5c64", 110 | "3": "#3d3846", 111 | "4": "#241f31", 112 | "5": "#000000" 113 | } 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /data/presets/pretty-purple.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Pretty Purple", 3 | "variables": { 4 | "accent_color": "#dc8add", 5 | "accent_bg_color": "#9141ac", 6 | "accent_fg_color": "#ffffff", 7 | "destructive_color": "#ff7b63", 8 | "destructive_bg_color": "#c01c28", 9 | "destructive_fg_color": "#ffffff", 10 | "success_color": "#8ff0a4", 11 | "success_bg_color": "#26a269", 12 | "success_fg_color": "#ffffff", 13 | "warning_color": "#f8e45c", 14 | "warning_bg_color": "#cd9309", 15 | "warning_fg_color": "rgba(0, 0, 0, 0.8)", 16 | "error_color": "#ff7b63", 17 | "error_bg_color": "#c01c28", 18 | "error_fg_color": "#ffffff", 19 | "window_bg_color": "#241f31", 20 | "window_fg_color": "#ffffff", 21 | "view_bg_color": "#363141", 22 | "view_fg_color": "#ffffff", 23 | "headerbar_bg_color": "#241f31", 24 | "headerbar_fg_color": "#ffffff", 25 | "headerbar_border_color": "#ffffff", 26 | "headerbar_backdrop_color": "@window_bg_color", 27 | "headerbar_shade_color": "rgba(0, 0, 0, 0.36)", 28 | "headerbar_darker_shade_color": "rgba(0, 0, 0, 0.9)", 29 | "card_bg_color": "rgba(255, 255, 255, 0.08)", 30 | "card_fg_color": "#ffffff", 31 | "card_shade_color": "rgba(0, 0, 0, 0.36)", 32 | "dialog_bg_color": "#241f31", 33 | "dialog_fg_color": "#ffffff", 34 | "popover_bg_color": "#241f31", 35 | "popover_fg_color": "#ffffff", 36 | "popover_shade_color": "rgba(0, 0, 0, 0.36)", 37 | "shade_color": "rgba(0, 0, 0, 0.36)", 38 | "scrollbar_outline_color": "rgba(0, 0, 0, 0.5)", 39 | "thumbnail_bg_color": "#241f31", 40 | "thumbnail_fg_color": "#ffffff", 41 | "sidebar_bg_color": "#39314e", 42 | "sidebar_fg_color": "#ffffff", 43 | "secondary_sidebar_bg_color": "#332b45", 44 | "secondary_sidebar_fg_color": "#ffffff", 45 | "sidebar_backdrop_color": "#332b45", 46 | "secondary_sidebar_backdrop_color": "#2c253c", 47 | "sidebar_shade_color": "rgba(0, 0, 0, 0.36)", 48 | "secondary_sidebar_shade_color": "rgba(0, 0, 0, 0.36)" 49 | }, 50 | "palette": { 51 | "blue_": { 52 | "1": "#99c1f1", 53 | "2": "#62a0ea", 54 | "3": "#3584e4", 55 | "4": "#1c71d8", 56 | "5": "#1a5fb4" 57 | }, 58 | "green_": { 59 | "1": "#8ff0a4", 60 | "2": "#57e389", 61 | "3": "#33d17a", 62 | "4": "#2ec27e", 63 | "5": "#26a269" 64 | }, 65 | "yellow_": { 66 | "1": "#f9f06b", 67 | "2": "#f8e45c", 68 | "3": "#f6d32d", 69 | "4": "#f5c211", 70 | "5": "#e5a50a" 71 | }, 72 | "orange_": { 73 | "1": "#ffbe6f", 74 | "2": "#ffa348", 75 | "3": "#ff7800", 76 | "4": "#e66100", 77 | "5": "#c64600" 78 | }, 79 | "red_": { 80 | "1": "#f66151", 81 | "2": "#ed333b", 82 | "3": "#e01b24", 83 | "4": "#c01c28", 84 | "5": "#a51d2d" 85 | }, 86 | "purple_": { 87 | "1": "#dc8add", 88 | "2": "#c061cb", 89 | "3": "#9141ac", 90 | "4": "#813d9c", 91 | "5": "#613583" 92 | }, 93 | "brown_": { 94 | "1": "#cdab8f", 95 | "2": "#b5835a", 96 | "3": "#986a44", 97 | "4": "#865e3c", 98 | "5": "#63452c" 99 | }, 100 | "light_": { 101 | "1": "#ffffff", 102 | "2": "#f6f5f4", 103 | "3": "#deddda", 104 | "4": "#c0bfbc", 105 | "5": "#9a9996" 106 | }, 107 | "dark_": { 108 | "1": "#77767b", 109 | "2": "#5e5c64", 110 | "3": "#3d3846", 111 | "4": "#241f31", 112 | "5": "#000000" 113 | } 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /data/shell/meson.build: -------------------------------------------------------------------------------- 1 | install_subdir('templates', 2 | install_dir: join_paths(get_option('datadir'), 'gradience', 'shell'), 3 | exclude_files: 'meson.build', 4 | strip_directory : false 5 | ) 6 | -------------------------------------------------------------------------------- /data/shell/templates/42/check-box.template: -------------------------------------------------------------------------------- 1 | /* Check Boxes */ 2 | 3 | // these are equal to the size of the SVG assets 4 | $check_height: 24px; 5 | $check_width: 24px; 6 | 7 | 8 | .check-box { 9 | StBoxLayout { spacing: .8em; } 10 | StBin { 11 | width: $check_width; 12 | height: $check_height; 13 | background-image: if($variant == 'light', url("resource:///org/gnome/shell/theme/checkbox-off-light.svg"), url("resource:///org/gnome/shell/theme/checkbox-off.svg")); 14 | } 15 | &:focus StBin { background-image: if($variant == 'light', url("resource:///org/gnome/shell/theme/checkbox-off-focused-light.svg"), url("resource:///org/gnome/shell/theme/checkbox-off-focused.svg"));; } 16 | &:checked StBin { background-image: url("resource:///org/gnome/shell/theme/checkbox.svg"); } 17 | &:focus:checked StBin { background-image: url("resource:///org/gnome/shell/theme/checkbox-focused.svg"); } 18 | } 19 | -------------------------------------------------------------------------------- /data/shell/templates/42/colors.template: -------------------------------------------------------------------------------- 1 | // When color definition differs for dark and light variant, 2 | // it gets @if-ed depending on $variant 3 | 4 | @import '_palette.scss'; 5 | 6 | $_dark_base_color: darken(desaturate({{bg_color}}, 2%), 2%); 7 | 8 | $base_color: $_dark_base_color; 9 | $bg_color: if($variant == 'light', darken($base_color, 5%), lighten($base_color, 5%)); 10 | $fg_color: if($variant == 'light', transparentize(black, .2), {{fg_color}}); 11 | 12 | $accent_fg_color: {{accent_fg_color}}; 13 | $selected_fg_color: if($variant == 'light', $accent_fg_color, {{selected_fg_color}}); 14 | $selected_bg_color: {{selected_bg_color}}; 15 | $selected_borders_color: if($variant == 'light', darken($selected_bg_color, 15%), darken($selected_bg_color, 30%)); // NOTE: Unused in GNOME Shell 42 16 | 17 | $borders_color: if($variant == 'light', transparentize($fg_color, .5), transparentize($fg_color, .9)); 18 | $borders_edge: if($variant == 'light', rgba(255,255,255,0.8), lighten($bg_color, 5%)); 19 | 20 | $link_color: if($variant == 'light', darken($selected_bg_color, 10%), lighten($selected_bg_color, 20%)); 21 | $link_visited_color: if($variant == 'light', darken($selected_bg_color, 20%), lighten($selected_bg_color, 10%)); // NOTE: Unused in GNOME Shell 42 22 | 23 | $warning_color: {{warning_bg_color}}; 24 | $error_color: {{error_bg_color}}; 25 | $success_color: {{success_bg_color}}; // NOTE: Unused in GNOME Shell 42 26 | $destructive_color: {{destructive_bg_color}}; 27 | 28 | // NOTE: Used also in overview for folder colors, in search results, partially in text and for indicators below app icons 29 | $osd_fg_color: {{osd_fg_color}}; 30 | $osd_bg_color: $_dark_base_color; // hardcoded for both light & dark 31 | $osd_insensitive_bg_color: transparentize(mix($osd_fg_color, opacify($osd_bg_color, 1), 10%), 0.5); // NOTE: Unused in GNOME Shell 42 32 | $osd_insensitive_fg_color: if($variant == 'light', mix($osd_fg_color, $osd_bg_color, 80%), mix($osd_fg_color, $osd_bg_color, 70%)); 33 | $osd_borders_color: transparentize(black, 0.3); 34 | $osd_outer_borders_color: transparentize($osd_fg_color, 0.98); 35 | 36 | $shadow_color: if($variant == 'light', rgba(0,0,0,0.1), rgba(0,0,0,0.2)); 37 | 38 | // cards 39 | $card_bg_color: if($variant == 'light', darken($bg_color, 5%), lighten($bg_color, 2%)); // TODO: Allow to modify this value 40 | 41 | // notifications 42 | $bubble_buttons_color: if($variant == 'light', darken($bg_color, 12%), lighten($bg_color, 10%)); 43 | 44 | // overview background color 45 | $system_bg_color: darken(desaturate({{system_bg_color}}, 2%), 2%); 46 | 47 | //insensitive state derived colors 48 | $insensitive_fg_color: mix($fg_color, $bg_color, 50%); 49 | $insensitive_bg_color: mix($bg_color, $base_color, 60%); 50 | $insensitive_borders_color: mix($borders_color, $base_color, 60%); // NOTE: Unused in GNOME Shell 42 51 | 52 | //colors for the backdrop state, derived from the main colors. 53 | // NOTE: This entire section doesn't seem to be used anywhere in GNOME Shell 42 54 | $backdrop_base_color: if($variant =='light', darken($base_color,1%), lighten($base_color,1%)); 55 | $backdrop_bg_color: $bg_color; 56 | $backdrop_fg_color: mix($fg_color, $backdrop_bg_color, 80%); 57 | $backdrop_insensitive_color: if($variant =='light', darken($backdrop_bg_color,15%), lighten($backdrop_bg_color,15%)); 58 | $backdrop_borders_color: mix($borders_color, $bg_color, 90%); 59 | $backdrop_dark_fill: mix($backdrop_borders_color,$backdrop_bg_color, 35%); 60 | 61 | // derived checked colors 62 | $checked_bg_color: if($variant=='light', darken($bg_color, 7%), lighten($bg_color, 7%)); 63 | $checked_fg_color: if($variant=='light', darken($fg_color, 7%), lighten($fg_color, 7%)); // NOTE: Unused in GNOME Shell 42 64 | 65 | // derived hover colors 66 | $hover_bg_color: if($variant=='light', darken($bg_color, 3%), lighten($bg_color, 10%)); 67 | $hover_fg_color: if($variant=='light', darken($fg_color, 5%), lighten($fg_color, 10%)); 68 | 69 | // derived active colors 70 | $active_bg_color: if($variant=='light', darken($bg_color, 5%), lighten($bg_color, 12%)); 71 | $active_fg_color: if($variant=='light', darken($fg_color, 5%), lighten($fg_color, 12%)); 72 | -------------------------------------------------------------------------------- /data/shell/templates/42/gnome-shell.template: -------------------------------------------------------------------------------- 1 | $variant: {{theme_variant}}; 2 | 3 | /* Generated with Gradience 4 | * 5 | * Issues caused by theming should be reported to Gradience repository, and not to upstream 6 | * 7 | * https://github.com/GradienceTeam/Gradience 8 | */ 9 | 10 | @import "gnome-shell-sass/_colors"; //use gtk colors 11 | @import "gnome-shell-sass/_drawing"; 12 | @import "gnome-shell-sass/_common"; 13 | @import "gnome-shell-sass/_widgets"; 14 | 15 | {{custom_css}} 16 | -------------------------------------------------------------------------------- /data/shell/templates/42/palette.template: -------------------------------------------------------------------------------- 1 | //GNOME Color Palette 2 | $blue_1: {{blue_1}}; 3 | $blue_2: {{blue_2}}; 4 | $blue_3: {{blue_3}}; 5 | $blue_4: {{blue_4}}; 6 | $blue_5: {{blue_5}}; 7 | $green_1: {{green_1}}; 8 | $green_2: {{green_2}}; 9 | $green_3: {{green_3}}; 10 | $green_4: {{green_4}}; 11 | $green_5: {{green_5}}; 12 | $yellow_1: {{yellow_1}}; 13 | $yellow_2: {{yellow_2}}; 14 | $yellow_3: {{yellow_3}}; 15 | $yellow_4: {{yellow_4}}; 16 | $yellow_5: {{yellow_5}}; 17 | $orange_1: {{orange_1}}; 18 | $orange_2: {{orange_2}}; 19 | $orange_3: {{orange_3}}; 20 | $orange_4: {{orange_4}}; 21 | $orange_5: {{orange_5}}; 22 | $red_1: {{red_1}}; 23 | $red_2: {{red_2}}; 24 | $red_3: {{red_3}}; 25 | $red_4: {{red_4}}; 26 | $red_5: {{red_5}}; 27 | $purple_1: {{purple_1}}; 28 | $purple_2: {{purple_2}}; 29 | $purple_3: {{purple_3}}; 30 | $purple_4: {{purple_4}}; 31 | $purple_5: {{purple_5}}; 32 | $brown_1: {{brown_1}}; 33 | $brown_2: {{brown_2}}; 34 | $brown_3: {{brown_3}}; 35 | $brown_4: {{brown_4}}; 36 | $brown_5: {{brown_5}}; 37 | $light_1: {{light_1}}; 38 | $light_2: {{light_2}}; 39 | $light_3: {{light_3}}; 40 | $light_4: {{light_4}}; 41 | $light_5: {{light_5}}; 42 | $dark_1: {{dark_1}}; 43 | $dark_2: {{dark_2}}; 44 | $dark_3: {{dark_3}}; 45 | $dark_4: {{dark_4}}; 46 | $dark_5: {{dark_5}}; 47 | -------------------------------------------------------------------------------- /data/shell/templates/42/switches.template: -------------------------------------------------------------------------------- 1 | /* Switches */ 2 | 3 | // these are equal to the size of the SVG assets 4 | $switch_height: 26px; 5 | $switch_width: 48px; 6 | 7 | .toggle-switch { 8 | color: $fg_color; 9 | height: $switch_height; 10 | width: $switch_width; 11 | background-size: contain; 12 | background-image: if($variant == 'light', url("resource:///org/gnome/shell/theme/toggle-off-light.svg"), url("resource:///org/gnome/shell/theme/toggle-off.svg")); 13 | &:checked { 14 | background-image: if($variant == 'light', url("resource:///org/gnome/shell/theme/toggle-on-light.svg"), url("asstets/toggle-on.svg")); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /data/shell/templates/43/check-box.template: -------------------------------------------------------------------------------- 1 | /* Check Boxes */ 2 | 3 | // these are equal to the size of the SVG assets 4 | $check_height: 24px; 5 | $check_width: 24px; 6 | 7 | 8 | .check-box { 9 | StBoxLayout { spacing: .8em; } 10 | StBin { 11 | width: $check_width; 12 | height: $check_height; 13 | background-image: if($variant == 'light', url("resource:///org/gnome/shell/theme/checkbox-off-light.svg"), url("resource:///org/gnome/shell/theme/checkbox-off.svg")); 14 | } 15 | &:focus StBin { background-image: if($variant == 'light', url("resource:///org/gnome/shell/theme/checkbox-off-focused-light.svg"), url("resource:///org/gnome/shell/theme/checkbox-off-focused.svg"));; } 16 | &:checked StBin { background-image: url("resource:///org/gnome/shell/theme/checkbox.svg"); } 17 | &:focus:checked StBin { background-image: url("resource:///org/gnome/shell/theme/checkbox-focused.svg"); } 18 | } 19 | -------------------------------------------------------------------------------- /data/shell/templates/43/gnome-shell.template: -------------------------------------------------------------------------------- 1 | $variant: {{theme_variant}}; 2 | 3 | /* Generated with Gradience 4 | * 5 | * Issues caused by theming should be reported to Gradience repository, and not to upstream 6 | * 7 | * https://github.com/GradienceTeam/Gradience 8 | */ 9 | 10 | @import "gnome-shell-sass/_colors"; //use gtk colors 11 | @import "gnome-shell-sass/_drawing"; 12 | @import "gnome-shell-sass/_common"; 13 | @import "gnome-shell-sass/_widgets"; 14 | 15 | {{custom_css}} 16 | -------------------------------------------------------------------------------- /data/shell/templates/43/palette.template: -------------------------------------------------------------------------------- 1 | //GNOME Color Palette 2 | $blue_1: {{blue_1}}; 3 | $blue_2: {{blue_2}}; 4 | $blue_3: {{blue_3}}; 5 | $blue_4: {{blue_4}}; 6 | $blue_5: {{blue_5}}; 7 | $green_1: {{green_1}}; 8 | $green_2: {{green_2}}; 9 | $green_3: {{green_3}}; 10 | $green_4: {{green_4}}; 11 | $green_5: {{green_5}}; 12 | $yellow_1: {{yellow_1}}; 13 | $yellow_2: {{yellow_2}}; 14 | $yellow_3: {{yellow_3}}; 15 | $yellow_4: {{yellow_4}}; 16 | $yellow_5: {{yellow_5}}; 17 | $orange_1: {{orange_1}}; 18 | $orange_2: {{orange_2}}; 19 | $orange_3: {{orange_3}}; 20 | $orange_4: {{orange_4}}; 21 | $orange_5: {{orange_5}}; 22 | $red_1: {{red_1}}; 23 | $red_2: {{red_2}}; 24 | $red_3: {{red_3}}; 25 | $red_4: {{red_4}}; 26 | $red_5: {{red_5}}; 27 | $purple_1: {{purple_1}}; 28 | $purple_2: {{purple_2}}; 29 | $purple_3: {{purple_3}}; 30 | $purple_4: {{purple_4}}; 31 | $purple_5: {{purple_5}}; 32 | $brown_1: {{brown_1}}; 33 | $brown_2: {{brown_2}}; 34 | $brown_3: {{brown_3}}; 35 | $brown_4: {{brown_4}}; 36 | $brown_5: {{brown_5}}; 37 | $light_1: {{light_1}}; 38 | $light_2: {{light_2}}; 39 | $light_3: {{light_3}}; 40 | $light_4: {{light_4}}; 41 | $light_5: {{light_5}}; 42 | $dark_1: {{dark_1}}; 43 | $dark_2: {{dark_2}}; 44 | $dark_3: {{dark_3}}; 45 | $dark_4: {{dark_4}}; 46 | $dark_5: {{dark_5}}; 47 | -------------------------------------------------------------------------------- /data/shell/templates/43/switches.template: -------------------------------------------------------------------------------- 1 | /* Switches */ 2 | 3 | // these are equal to the size of the SVG assets 4 | $switch_height: 26px; 5 | $switch_width: 48px; 6 | 7 | .toggle-switch { 8 | color: $fg_color; 9 | height: $switch_height; 10 | width: $switch_width; 11 | background-size: contain; 12 | background-image: if($variant == 'light', url("resource:///org/gnome/shell/theme/toggle-off-light.svg"), url("resource:///org/gnome/shell/theme/toggle-off.svg")); 13 | &:checked { 14 | background-image: if($variant == 'light', url("resource:///org/gnome/shell/theme/toggle-on-light.svg"), url("assets/toggle-on.svg")); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /data/shell/templates/44/check-box.template: -------------------------------------------------------------------------------- 1 | /* Check Boxes */ 2 | 3 | // these are equal to the size of the SVG assets 4 | $check_height: 24px; 5 | $check_width: 24px; 6 | 7 | 8 | .check-box { 9 | StBoxLayout { spacing: .8em; } 10 | StBin { 11 | width: $check_width; 12 | height: $check_height; 13 | background-image: if($variant == 'light', url("resource:///org/gnome/shell/theme/checkbox-off-light.svg"), url("resource:///org/gnome/shell/theme/checkbox-off.svg")); 14 | } 15 | &:focus StBin { background-image: if($variant == 'light', url("resource:///org/gnome/shell/theme/checkbox-off-focused-light.svg"), url("resource:///org/gnome/shell/theme/checkbox-off-focused.svg"));; } 16 | &:checked StBin { background-image: url("resource:///org/gnome/shell/theme/checkbox.svg"); } 17 | &:focus:checked StBin { background-image: url("resource:///org/gnome/shell/theme/checkbox-focused.svg"); } 18 | } 19 | -------------------------------------------------------------------------------- /data/shell/templates/44/colors.template: -------------------------------------------------------------------------------- 1 | // When color definition differs for dark and light variant, 2 | // it gets @if-ed depending on $variant 3 | 4 | @import '_palette.scss'; 5 | 6 | $is_highcontrast: false; 7 | 8 | $_dark_base_color: darken(desaturate({{bg_color}}, 2%), 2%); 9 | 10 | $base_color: $_dark_base_color; 11 | $bg_color: if($variant == 'light', darken($base_color, 5%), lighten($base_color, 5%)); 12 | $fg_color: if($variant == 'light', transparentize(black, .2), {{fg_color}}); 13 | 14 | $accent_fg_color: {{accent_fg_color}}; 15 | $selected_fg_color: if($variant == 'light', $accent_fg_color, {{selected_fg_color}}); 16 | $selected_bg_color: {{selected_bg_color}}; 17 | $selected_borders_color: if($variant == 'light', darken($selected_bg_color, 15%), darken($selected_bg_color, 30%)); 18 | 19 | $borders_color: if($variant == 'light', transparentize($fg_color, .5), transparentize($fg_color, .9)); 20 | $outer_borders_color: if($variant == 'light', rgba(255,255,255,0.8), lighten($bg_color, 5%)); 21 | 22 | $link_color: if($variant == 'light', darken($selected_bg_color, 10%), lighten($selected_bg_color, 20%)); 23 | $link_visited_color: if($variant == 'light', darken($selected_bg_color, 20%), lighten($selected_bg_color, 10%)); // NOTE: Unused in GNOME Shell 44 24 | 25 | $warning_color: {{warning_bg_color}}; 26 | $error_color: {{error_bg_color}}; 27 | $success_color: {{success_bg_color}}; // NOTE: Unused in GNOME Shell 44 28 | $destructive_color: {{destructive_bg_color}}; 29 | 30 | // NOTE: Used also in overview for folder colors, in search results, partially in text and for indicators below app icons 31 | $osd_fg_color: {{osd_fg_color}}; 32 | $osd_bg_color: $_dark_base_color; // hardcoded for both light & dark 33 | $osd_insensitive_bg_color: transparentize(mix($osd_fg_color, opacify($osd_bg_color, 1), 10%), 0.5); // NOTE: Unused in GNOME Shell 44 34 | $osd_insensitive_fg_color: if($variant == 'light', mix($osd_fg_color, $osd_bg_color, 80%), mix($osd_fg_color, $osd_bg_color, 70%)); 35 | $osd_borders_color: transparentize(black, 0.3); 36 | $osd_outer_borders_color: transparentize($osd_fg_color, 0.9); 37 | 38 | $shadow_color: if($variant == 'light', rgba(0,0,0,0.1), rgba(0,0,0,0.2)); 39 | 40 | // button 41 | $button_mix_factor: 9%; 42 | 43 | // notifications 44 | $bubble_buttons_color: if($variant == 'light', darken($bg_color, 7%), lighten($bg_color, 5%)); 45 | 46 | // overview background color 47 | $system_bg_color: darken(desaturate({{system_bg_color}}, 2%), 2%); 48 | 49 | //insensitive state derived colors 50 | $insensitive_fg_color: mix($fg_color, $bg_color, 50%); 51 | $insensitive_bg_color: mix($bg_color, $base_color, 60%); 52 | $insensitive_borders_color: mix($borders_color, $base_color, 60%); // NOTE: Unused in GNOME Shell 44 53 | 54 | //colors for the backdrop state, derived from the main colors. 55 | // NOTE: This entire section doesn't seem to be used anywhere in GNOME Shell 44 56 | $backdrop_base_color: if($variant =='light', darken($base_color,1%), lighten($base_color,1%)); 57 | $backdrop_bg_color: $bg_color; 58 | $backdrop_fg_color: mix($fg_color, $backdrop_bg_color, 80%); 59 | $backdrop_insensitive_color: if($variant =='light', darken($backdrop_bg_color,15%), lighten($backdrop_bg_color,15%)); 60 | $backdrop_borders_color: mix($borders_color, $bg_color, 90%); 61 | $backdrop_dark_fill: mix($backdrop_borders_color,$backdrop_bg_color, 35%); 62 | 63 | // derived checked colors 64 | $checked_bg_color: if($variant=='light', darken($bg_color, 7%), lighten($bg_color, 7%)); 65 | $checked_fg_color: if($variant=='light', darken($fg_color, 7%), lighten($fg_color, 7%)); // NOTE: Unused in GNOME Shell 44 66 | 67 | // derived hover colors 68 | $hover_bg_color: if($variant=='light', darken($bg_color, 3%), lighten($bg_color, 10%)); 69 | $hover_fg_color: if($variant=='light', darken($fg_color, 5%), lighten($fg_color, 10%)); 70 | 71 | // derived active colors 72 | $active_bg_color: if($variant=='light', darken($bg_color, 5%), lighten($bg_color, 12%)); 73 | $active_fg_color: if($variant=='light', darken($fg_color, 5%), lighten($fg_color, 12%)); 74 | -------------------------------------------------------------------------------- /data/shell/templates/44/gnome-shell.template: -------------------------------------------------------------------------------- 1 | $variant: {{theme_variant}}; 2 | 3 | /* Generated with Gradience 4 | * 5 | * Issues caused by theming should be reported to Gradience repository, and not to upstream 6 | * 7 | * https://github.com/GradienceTeam/Gradience 8 | */ 9 | 10 | @import "gnome-shell-sass/_colors"; //use gtk colors 11 | @import "gnome-shell-sass/_drawing"; 12 | @import "gnome-shell-sass/_common"; 13 | @import "gnome-shell-sass/_widgets"; 14 | 15 | {{custom_css}} 16 | -------------------------------------------------------------------------------- /data/shell/templates/44/palette.template: -------------------------------------------------------------------------------- 1 | //GNOME Color Palette 2 | $blue_1: {{blue_1}}; 3 | $blue_2: {{blue_2}}; 4 | $blue_3: {{blue_3}}; 5 | $blue_4: {{blue_4}}; 6 | $blue_5: {{blue_5}}; 7 | $green_1: {{green_1}}; 8 | $green_2: {{green_2}}; 9 | $green_3: {{green_3}}; 10 | $green_4: {{green_4}}; 11 | $green_5: {{green_5}}; 12 | $yellow_1: {{yellow_1}}; 13 | $yellow_2: {{yellow_2}}; 14 | $yellow_3: {{yellow_3}}; 15 | $yellow_4: {{yellow_4}}; 16 | $yellow_5: {{yellow_5}}; 17 | $orange_1: {{orange_1}}; 18 | $orange_2: {{orange_2}}; 19 | $orange_3: {{orange_3}}; 20 | $orange_4: {{orange_4}}; 21 | $orange_5: {{orange_5}}; 22 | $red_1: {{red_1}}; 23 | $red_2: {{red_2}}; 24 | $red_3: {{red_3}}; 25 | $red_4: {{red_4}}; 26 | $red_5: {{red_5}}; 27 | $purple_1: {{purple_1}}; 28 | $purple_2: {{purple_2}}; 29 | $purple_3: {{purple_3}}; 30 | $purple_4: {{purple_4}}; 31 | $purple_5: {{purple_5}}; 32 | $brown_1: {{brown_1}}; 33 | $brown_2: {{brown_2}}; 34 | $brown_3: {{brown_3}}; 35 | $brown_4: {{brown_4}}; 36 | $brown_5: {{brown_5}}; 37 | $light_1: {{light_1}}; 38 | $light_2: {{light_2}}; 39 | $light_3: {{light_3}}; 40 | $light_4: {{light_4}}; 41 | $light_5: {{light_5}}; 42 | $dark_1: {{dark_1}}; 43 | $dark_2: {{dark_2}}; 44 | $dark_3: {{dark_3}}; 45 | $dark_4: {{dark_4}}; 46 | $dark_5: {{dark_5}}; 47 | -------------------------------------------------------------------------------- /data/shell/templates/44/switches.template: -------------------------------------------------------------------------------- 1 | /* Switches */ 2 | 3 | // these are equal to the size of the SVG assets 4 | $switch_height: 26px; 5 | $switch_width: 48px; 6 | 7 | .toggle-switch { 8 | color: $fg_color; 9 | height: $switch_height; 10 | width: $switch_width; 11 | background-size: contain; 12 | background-image: if($variant == 'light', url("resource:///org/gnome/shell/theme/toggle-off-light.svg"), url("resource:///org/gnome/shell/theme/toggle-off.svg")); 13 | &:checked { 14 | background-image: if($variant == 'light', url("resource:///org/gnome/shell/theme/toggle-on-light.svg"), url("assets/toggle-on.svg")); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /data/shell/templates/45/check-box.template: -------------------------------------------------------------------------------- 1 | /* Check Boxes */ 2 | 3 | // these are equal to the size of the SVG assets 4 | $check_height: 24px; 5 | $check_width: 24px; 6 | 7 | 8 | .check-box { 9 | StBoxLayout { spacing: .8em; } 10 | StBin { 11 | width: $check_width; 12 | height: $check_height; 13 | background-image: if($variant == 'light', url("resource:///org/gnome/shell/theme/checkbox-off-light.svg"), url("resource:///org/gnome/shell/theme/checkbox-off.svg")); 14 | } 15 | &:focus StBin { background-image: if($variant == 'light', url("resource:///org/gnome/shell/theme/checkbox-off-focused-light.svg"), url("resource:///org/gnome/shell/theme/checkbox-off-focused.svg"));; } 16 | &:checked StBin { background-image: url("resource:///org/gnome/shell/theme/checkbox.svg"); } 17 | &:focus:checked StBin { background-image: url("resource:///org/gnome/shell/theme/checkbox-focused.svg"); } 18 | } 19 | -------------------------------------------------------------------------------- /data/shell/templates/45/gnome-shell.template: -------------------------------------------------------------------------------- 1 | $variant: {{theme_variant}}; 2 | 3 | /* Generated with Gradience 4 | * 5 | * Issues caused by theming should be reported to Gradience repository, and not to upstream 6 | * 7 | * https://github.com/GradienceTeam/Gradience 8 | */ 9 | 10 | @import "gnome-shell-sass/_colors"; //use gtk colors 11 | @import "gnome-shell-sass/_drawing"; 12 | @import "gnome-shell-sass/_common"; 13 | @import "gnome-shell-sass/_widgets"; 14 | 15 | {{custom_css}} 16 | -------------------------------------------------------------------------------- /data/shell/templates/45/palette.template: -------------------------------------------------------------------------------- 1 | //GNOME Color Palette 2 | $blue_1: {{blue_1}}; 3 | $blue_2: {{blue_2}}; 4 | $blue_3: {{blue_3}}; 5 | $blue_4: {{blue_4}}; 6 | $blue_5: {{blue_5}}; 7 | $green_1: {{green_1}}; 8 | $green_2: {{green_2}}; 9 | $green_3: {{green_3}}; 10 | $green_4: {{green_4}}; 11 | $green_5: {{green_5}}; 12 | $yellow_1: {{yellow_1}}; 13 | $yellow_2: {{yellow_2}}; 14 | $yellow_3: {{yellow_3}}; 15 | $yellow_4: {{yellow_4}}; 16 | $yellow_5: {{yellow_5}}; 17 | $orange_1: {{orange_1}}; 18 | $orange_2: {{orange_2}}; 19 | $orange_3: {{orange_3}}; 20 | $orange_4: {{orange_4}}; 21 | $orange_5: {{orange_5}}; 22 | $red_1: {{red_1}}; 23 | $red_2: {{red_2}}; 24 | $red_3: {{red_3}}; 25 | $red_4: {{red_4}}; 26 | $red_5: {{red_5}}; 27 | $purple_1: {{purple_1}}; 28 | $purple_2: {{purple_2}}; 29 | $purple_3: {{purple_3}}; 30 | $purple_4: {{purple_4}}; 31 | $purple_5: {{purple_5}}; 32 | $brown_1: {{brown_1}}; 33 | $brown_2: {{brown_2}}; 34 | $brown_3: {{brown_3}}; 35 | $brown_4: {{brown_4}}; 36 | $brown_5: {{brown_5}}; 37 | $light_1: {{light_1}}; 38 | $light_2: {{light_2}}; 39 | $light_3: {{light_3}}; 40 | $light_4: {{light_4}}; 41 | $light_5: {{light_5}}; 42 | $dark_1: {{dark_1}}; 43 | $dark_2: {{dark_2}}; 44 | $dark_3: {{dark_3}}; 45 | $dark_4: {{dark_4}}; 46 | $dark_5: {{dark_5}}; 47 | -------------------------------------------------------------------------------- /data/shell/templates/45/switches.template: -------------------------------------------------------------------------------- 1 | /* Switches */ 2 | 3 | // these are equal to the size of the SVG assets 4 | $switch_height: 26px; 5 | $switch_width: 48px; 6 | 7 | .toggle-switch { 8 | color: $fg_color; 9 | height: $switch_height; 10 | width: $switch_width; 11 | background-size: contain; 12 | background-image: if($variant == 'light', url("resource:///org/gnome/shell/theme/toggle-off-light.svg"), url("resource:///org/gnome/shell/theme/toggle-off.svg")); 13 | &:checked { 14 | background-image: if($variant == 'light', url("resource:///org/gnome/shell/theme/toggle-on-light.svg"), url("assets/toggle-on.svg")); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /data/style.css: -------------------------------------------------------------------------------- 1 | .variant { 2 | padding: 0; 3 | border-radius: 100%; 4 | } 5 | 6 | .variant radio { 7 | color: transparent; 8 | background-color: inherit; 9 | border: 2px solid transparent; 10 | } 11 | 12 | .variant:checked radio { 13 | border: 2px solid @accent_bg_color; 14 | } 15 | 16 | #dark { 17 | background-color: #3d3846; 18 | } 19 | 20 | #light { 21 | background-color: #deddda; 22 | } 23 | 24 | #red { 25 | background-color: #e01b24; 26 | } 27 | 28 | #orange { 29 | background-color: #ff7800; 30 | } 31 | 32 | #yellow { 33 | background-color: #f6d32d; 34 | } 35 | 36 | #blue { 37 | background-color: #3584e4; 38 | } 39 | 40 | #green { 41 | background-color: #33d17a; 42 | } 43 | 44 | .tag { 45 | border-radius: 20px; 46 | background-color: alpha(currentColor, 0.07); 47 | padding: 5px 13px; 48 | margin: 0 2px; 49 | } 50 | 51 | .badge-black { 52 | background-color: #3d3846; 53 | color: #deddda; 54 | } 55 | .badge-white { 56 | background-color: #deddda; 57 | color: #3d3846; 58 | } 59 | 60 | .row-content { 61 | padding: 10px; 62 | } 63 | 64 | .content { 65 | margin: 10px 12px; 66 | } 67 | -------------------------------------------------------------------------------- /data/ui/app_type_dialog.blp: -------------------------------------------------------------------------------- 1 | using Gtk 4.0; 2 | using Adw 1; 3 | 4 | template $GradienceAppTypeDialog : Adw.MessageDialog { 5 | [extra-child] 6 | Box { 7 | orientation: vertical; 8 | spacing: 15; 9 | 10 | Box { 11 | orientation: vertical; 12 | Label { 13 | styles ["heading"] 14 | label: _("Select application types to theme:"); 15 | } 16 | CheckButton gtk4-app-type { 17 | label: _("Libadwaita and GTK 4 Applications"); 18 | active: true; 19 | } 20 | CheckButton gtk3-app-type { 21 | label: _("GTK 3 Applications (adw-gtk3 theme required)"); 22 | } 23 | } 24 | // Box { 25 | // orientation: vertical; 26 | // Label { 27 | // styles ["heading"] 28 | // label: _("Select color mode to theme:"); 29 | // } 30 | // CheckButton dark { 31 | // label: _("Dark"); 32 | // active: true; 33 | // } 34 | // CheckButton light { 35 | // label: _("Light"); 36 | // } 37 | // } 38 | } 39 | } 40 | 41 | -------------------------------------------------------------------------------- /data/ui/builtin_preset_row.blp: -------------------------------------------------------------------------------- 1 | using Gtk 4.0; 2 | using Adw 1; 3 | 4 | template $GradienceBuiltinPresetRow : Adw.ActionRow { 5 | subtitle: _("Made by @GradienceTeam"); 6 | activatable-widget: apply_button; 7 | 8 | [suffix] 9 | Button apply_button { 10 | valign: center; 11 | icon-name: "checkmark-symbolic"; 12 | tooltip-text: _("Apply Preset"); 13 | clicked => $on_apply_button_clicked(); 14 | styles [ 15 | "flat", 16 | ] 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /data/ui/custom_css_group.blp: -------------------------------------------------------------------------------- 1 | using Gtk 4.0; 2 | using Adw 1; 3 | 4 | template $GradienceCustomCSSGroup : Adw.PreferencesGroup { 5 | title: _("Custom Styles"); 6 | description: _("Changing this may break some programs. Libadwaita allows applications to hardcode values like padding and margins, and using custom styles may cause unintended breakage."); 7 | 8 | [header-suffix] 9 | DropDown app_type_dropdown { 10 | valign: start; 11 | model: app_type_list; 12 | notify => $on_dropdown_notify(); 13 | } 14 | 15 | ScrolledWindow { 16 | min-content-height: 500; 17 | max-content-height: 500; 18 | TextView custom_css_text_view { 19 | styles ["card"] 20 | left-margin: 10; 21 | right-margin: 10; 22 | top-margin: 10; 23 | bottom-margin: 10; 24 | monospace: true; 25 | buffer: TextBuffer { 26 | changed => $on_custom_css_changed(); 27 | }; 28 | } 29 | } 30 | } 31 | 32 | StringList app_type_list { 33 | strings [_("GTK 4"), _("GTK 3")] 34 | } 35 | -------------------------------------------------------------------------------- /data/ui/error_list_row.blp: -------------------------------------------------------------------------------- 1 | using Gtk 4.0; 2 | using Adw 1; 3 | 4 | template $GradienceErrorListRow : ListBoxRow { 5 | Box { 6 | orientation: vertical; 7 | margin-top: 6; 8 | margin-bottom: 6; 9 | margin-start: 6; 10 | margin-end: 6; 11 | 12 | Box { 13 | orientation: horizontal; 14 | spacing: 6; 15 | 16 | Label error-label { 17 | halign: start; 18 | justify: left; 19 | styles ["heading", "error"] 20 | } 21 | 22 | Label element-label { 23 | halign: start; 24 | justify: left; 25 | styles ["dim-label", "error"] 26 | } 27 | } 28 | 29 | Label line-label { 30 | halign: start; 31 | wrap: true; 32 | justify: left; 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /data/ui/explore_preset_row.blp: -------------------------------------------------------------------------------- 1 | using Gtk 4.0; 2 | using Adw 1; 3 | 4 | template $GradienceExplorePresetRow : Adw.ActionRow { 5 | activatable-widget: apply_button; 6 | 7 | Box { 8 | spacing: 6; 9 | 10 | //Label badge { 11 | // valign: center; 12 | // label: _("Unknown"); 13 | 14 | // styles [ 15 | // "tag", 16 | // "caption", 17 | // ] 18 | //} 19 | 20 | Button apply_button { 21 | valign: center; 22 | icon-name: "checkmark-symbolic"; 23 | tooltip-text: _("Download and Apply"); 24 | clicked => $on_apply_button_clicked(); 25 | 26 | styles [ 27 | "flat", 28 | ] 29 | } 30 | 31 | Button download_button { 32 | valign: center; 33 | icon-name: "folder-download-symbolic"; 34 | tooltip-text: _("Download"); 35 | clicked => $on_download_button_clicked(); 36 | 37 | styles [ 38 | "flat", 39 | ] 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /data/ui/help_overlay.blp: -------------------------------------------------------------------------------- 1 | using Gtk 4.0; 2 | 3 | ShortcutsWindow help_overlay { 4 | modal: true; 5 | 6 | ShortcutsSection { 7 | section-name: "shortcuts"; 8 | ShortcutsGroup { 9 | title: C_("shortcut window", "General"); 10 | 11 | ShortcutsShortcut { 12 | title: C_("shortcut window", "Show Shortcuts"); 13 | action-name: "win.show-help-overlay"; 14 | } 15 | 16 | ShortcutsShortcut { 17 | title: C_("shortcut window", "Show Apply Dialog"); 18 | action-name: "app.apply_color_scheme"; 19 | } 20 | 21 | ShortcutsShortcut { 22 | title: C_("shortcut window", "Manage Presets"); 23 | action-name: "app.manage_presets"; 24 | } 25 | 26 | ShortcutsShortcut { 27 | title: C_("shortcut window", "Save Preset"); 28 | action-name: "app.save_preset"; 29 | } 30 | 31 | ShortcutsShortcut { 32 | title: C_("shortcut window", "Go to the Colors Section"); 33 | action-name: "app.switch_to_colors_page"; 34 | } 35 | 36 | ShortcutsShortcut { 37 | title: C_("shortcut window", "Go to the Theming Section"); 38 | action-name: "app.switch_to_theming_page"; 39 | } 40 | 41 | ShortcutsShortcut { 42 | title: C_("shortcut window", "Go to the Advanced Section"); 43 | action-name: "app.switch_to_advanced_page"; 44 | } 45 | 46 | ShortcutsShortcut { 47 | title: C_("shortcut window", "Preferences"); 48 | action-name: "app.preferences"; 49 | } 50 | 51 | ShortcutsShortcut { 52 | title: C_("shortcut window", "Quit"); 53 | action-name: "app.quit"; 54 | } 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /data/ui/log_out_dialog.blp: -------------------------------------------------------------------------------- 1 | using Gtk 4.0; 2 | using Adw 1; 3 | 4 | template $GradienceLogOutDialog : Adw.MessageDialog { 5 | heading: _("Log out"); // TODO: redundant? how can we not repeat ourselves? 6 | body: _("Log out to allow changes to take effect."); 7 | } 8 | -------------------------------------------------------------------------------- /data/ui/meson.build: -------------------------------------------------------------------------------- 1 | blueprints = custom_target('blueprints', 2 | input: files( 3 | 'error_list_row.blp', 4 | 'palette_shades.blp', 5 | 'option_row.blp', 6 | 'window.blp', 7 | 'monet_theming_group.blp', 8 | 'app_type_dialog.blp', 9 | 'custom_css_group.blp', 10 | 'presets_manager_window.blp', 11 | 'reset_preset_group.blp', 12 | 'preferences_window.blp', 13 | 'plugin_row.blp', 14 | 'welcome_window.blp', 15 | 'preset_row.blp', 16 | 'builtin_preset_row.blp', 17 | 'explore_preset_row.blp', 18 | 'help_overlay.blp', 19 | 'save_dialog.blp', 20 | 'shell_prefs_window.blp', 21 | 'shell_theming_group.blp', 22 | 'repo_row.blp', 23 | 'no_plugin_window.blp', 24 | 'share_window.blp', 25 | 'theming_empty_group.blp', 26 | ), 27 | output: '.', 28 | command: [find_program('blueprint-compiler'), 'batch-compile', '@OUTPUT@', '@CURRENT_SOURCE_DIR@', '@INPUT@'] 29 | ) 30 | -------------------------------------------------------------------------------- /data/ui/monet_theming_group.blp: -------------------------------------------------------------------------------- 1 | using Gtk 4.0; 2 | using Adw 1; 3 | 4 | template $GradienceMonetThemingGroup : Adw.PreferencesGroup { 5 | title: _("Monet Engine"); 6 | description: _("Generates a Material Design 3 palette by extracting colors of an image."); 7 | 8 | Adw.ExpanderRow monet-theming-expander { 9 | title: _("Monet Engine Options"); 10 | subtitle: _("Choose an image and modify generated Monet palette"); 11 | expanded: true; 12 | 13 | [action] 14 | Button monet-apply-button { 15 | valign: center; 16 | label: _("Apply"); 17 | tooltip-text: _("Apply a palette"); 18 | clicked => $on_apply_button_clicked(); 19 | styles ["suggested-action"] 20 | } 21 | 22 | Adw.ActionRow file-chooser-row { 23 | title: _("Background Image"); 24 | activatable-widget: file-chooser-button; 25 | 26 | [suffix] 27 | Button file-chooser-button { 28 | valign: center; 29 | clicked => $on_file_chooser_button_clicked(); 30 | 31 | Adw.ButtonContent { 32 | icon-name: "folder-pictures-symbolic"; 33 | label: _("Choose a File"); 34 | use-underline: true; 35 | } 36 | } 37 | } 38 | } 39 | } 40 | 41 | Gtk.FileChooserNative monet-file-chooser { 42 | title: _("Choose a Image File"); 43 | modal: true; 44 | //response => on_monet_file_chooser_response(); 45 | } 46 | 47 | -------------------------------------------------------------------------------- /data/ui/no_plugin_window.blp: -------------------------------------------------------------------------------- 1 | using Gtk 4.0; 2 | using Adw 1; 3 | 4 | template $GradienceNoPluginPrefWindow : Adw.PreferencesWindow { 5 | title: _("Plugin Preferences"); 6 | search-enabled: false; 7 | default-height: 400; 8 | default-width: 400; 9 | modal: true; 10 | 11 | Adw.PreferencesPage { 12 | Adw.StatusPage { 13 | name: "empty"; 14 | icon-name: "action-unavailable-symbolic"; 15 | title: _("No Preferences"); 16 | description: _("This plugin has no preferences."); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /data/ui/option_row.blp: -------------------------------------------------------------------------------- 1 | using Gtk 4.0; 2 | using Adw 1; 3 | 4 | template $GradienceOptionRow : Adw.ActionRow { 5 | activatable-widget: color-value; 6 | 7 | [suffix] 8 | MenuButton warning-button { 9 | valign: center; 10 | icon-name: "adw-gtk3-warning-symbolic"; 11 | popover: warning-popover; 12 | tooltip-text: _("GTK 3 Support Warning"); 13 | styles ["flat"] 14 | } 15 | 16 | [suffix] 17 | MenuButton explanation-button { 18 | valign: center; 19 | icon-name: "dialog-information-symbolic"; 20 | popover: explanation-popover; 21 | tooltip-text: _("Explanation"); 22 | styles ["flat"] 23 | } 24 | 25 | [suffix] 26 | Stack value-stack { 27 | valign: center; 28 | hhomogeneous: false; 29 | interpolate-size: true; 30 | transition-type: crossfade; 31 | 32 | ColorButton color-value { 33 | rgba: "#00000000"; 34 | use-alpha: true; 35 | } 36 | Entry text-value { 37 | text: "#00000000"; 38 | } 39 | } 40 | 41 | [suffix] 42 | ToggleButton text-value-toggle { 43 | valign: center; 44 | icon-name: "document-edit-symbolic"; 45 | tooltip-text: _("Show Hex"); 46 | styles ["flat"] 47 | 48 | toggled => $on_text_value_toggled(); 49 | } 50 | } 51 | 52 | Popover warning-popover { 53 | autohide: true; 54 | Label warning-label { 55 | margin-top: 6; 56 | margin-bottom: 6; 57 | margin-start: 6; 58 | margin-end: 6; 59 | max-width-chars: 30; 60 | wrap: true; 61 | justify: center; 62 | } 63 | } 64 | 65 | Popover explanation-popover { 66 | autohide: true; 67 | Label explanation-label { 68 | margin-top: 6; 69 | margin-bottom: 6; 70 | margin-start: 6; 71 | margin-end: 6; 72 | max-width-chars: 30; 73 | wrap: true; 74 | justify: center; 75 | } 76 | } 77 | 78 | -------------------------------------------------------------------------------- /data/ui/palette_shades.blp: -------------------------------------------------------------------------------- 1 | using Gtk 4.0; 2 | using Adw 1; 3 | 4 | template $GradiencePaletteShades : Adw.ActionRow {} 5 | -------------------------------------------------------------------------------- /data/ui/plugin_row.blp: -------------------------------------------------------------------------------- 1 | using Gtk 4.0; 2 | using Adw 1; 3 | 4 | template $GradiencePluginRow : Adw.ActionRow { 5 | activatable-widget: switch; 6 | 7 | [suffix] 8 | Switch switch { 9 | valign: center; 10 | tooltip-text: _("Toggle Plugin"); 11 | state-set => $on_switch_toggled(); 12 | } 13 | 14 | // TODO: Detect if plugin has preferences, and if it does display the 15 | // settings button 16 | 17 | // [suffix] 18 | // Button settings-button { 19 | // valign: center; 20 | // icon-name: "settings-symbolic"; 21 | // tooltip-text: _("Preferences"); 22 | // clicked => $on_settings_plugin_clicked(); 23 | 24 | // styles [ 25 | // "flat", 26 | // ] 27 | // } 28 | 29 | [suffix] 30 | Button remove-button { 31 | valign: center; 32 | icon-name: "user-trash-symbolic"; 33 | tooltip-text: _("Remove Plugin"); 34 | clicked => $on_remove_plugin_clicked(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /data/ui/repo_row.blp: -------------------------------------------------------------------------------- 1 | using Gtk 4.0; 2 | using Adw 1; 3 | 4 | template $GradienceRepoRow : Adw.ActionRow { 5 | [suffix] 6 | Button remove_button { 7 | valign: center; 8 | icon-name: "user-trash-symbolic"; 9 | tooltip-text: _("Remove Preset"); 10 | clicked => $on_remove_button_clicked(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /data/ui/reset_preset_group.blp: -------------------------------------------------------------------------------- 1 | using Gtk 4.0; 2 | using Adw 1; 3 | 4 | template $GradienceResetPresetGroup : Adw.PreferencesGroup { 5 | title: _("Reset and Restore Theming"); 6 | description: _("Reset theming to default or restore previously applied preset."); 7 | 8 | Adw.ActionRow { 9 | title: _("GTK 4/Libadwaita Apps"); 10 | 11 | Button restore_libadw_button { 12 | valign: center; 13 | icon-name: "edit-undo-symbolic"; 14 | tooltip-text: _("Restore Previous Preset"); 15 | clicked => $on_libadw_restore_button_clicked(); 16 | styles ["flat"] 17 | } 18 | 19 | Button reset_libadw_button { 20 | valign: center; 21 | label: _("Reset"); 22 | tooltip-text: _("Reset Applied Preset"); 23 | clicked => $on_libadw_reset_button_clicked(); 24 | styles ["destructive-action"] 25 | } 26 | } 27 | 28 | Adw.ActionRow { 29 | title: _("GTK 3 Apps"); 30 | 31 | Button restore_gtk3_button { 32 | valign: center; 33 | icon-name: "edit-undo-symbolic"; 34 | tooltip-text: _("Restore Previous Preset"); 35 | clicked => $on_gtk3_restore_button_clicked(); 36 | styles ["flat"] 37 | } 38 | 39 | Button reset_gtk3_button { 40 | valign: center; 41 | label: _("Reset"); 42 | tooltip-text: _("Reset Applied Preset"); 43 | clicked => $on_gtk3_reset_button_clicked(); 44 | styles ["destructive-action"] 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /data/ui/save_dialog.blp: -------------------------------------------------------------------------------- 1 | using Gtk 4.0; 2 | using Adw 1; 3 | 4 | template $GradienceSaveDialog : Adw.MessageDialog { 5 | heading: _("Save preset as…"); 6 | body-use-markup: true; 7 | 8 | [extra-child] 9 | Entry preset-entry { 10 | placeholder-text: _("Preset Name"); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /data/ui/shell_prefs_window.blp: -------------------------------------------------------------------------------- 1 | using Gtk 4.0; 2 | using Adw 1; 3 | 4 | template $GradienceShellPrefsWindow : Adw.PreferencesWindow { 5 | title: _("Shell Engine Preferences"); 6 | search-enabled: false; 7 | default-height: 620; 8 | default-width: 500; 9 | modal: true; 10 | 11 | Adw.PreferencesPage { 12 | Adw.PreferencesGroup custom-colors-group { 13 | title: _("Shell theme colors"); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /data/ui/shell_theming_group.blp: -------------------------------------------------------------------------------- 1 | using Gtk 4.0; 2 | using Adw 1; 3 | 4 | template $GradienceShellThemingGroup: Adw.PreferencesGroup { 5 | title: _("Shell Engine"); 6 | description: _("Generates GNOME Shell theme based on current preset.\nWARNING: Extensions that modify the Shell stylesheet may cause issues with themes."); 7 | 8 | // TODO: Fix the warning being under shell-theming-expander 9 | Label { 10 | label: "Warning: Extensions that modify the Shell stylesheet may cause issues with themes"; 11 | halign: start; 12 | 13 | styles [ 14 | "dim-label", 15 | "warning" 16 | ] 17 | } 18 | 19 | Adw.ExpanderRow shell-theming-expander { 20 | title: _("Shell Engine Options"); 21 | subtitle: _("Change the generated GNOME Shell theme"); 22 | expanded: true; 23 | 24 | [action] 25 | Button shell-apply-button { 26 | valign: center; 27 | label: _("Apply"); 28 | tooltip-text: _("Apply Shell theme"); 29 | clicked => $on_apply_button_clicked(); 30 | 31 | styles [ 32 | "suggested-action" 33 | ] 34 | } 35 | 36 | Adw.ActionRow custom-colors-row { 37 | title: _("Customize Shell Theme"); 38 | activatable-widget: custom-colors-button; 39 | 40 | [suffix] 41 | Button custom-colors-button { 42 | valign: center; 43 | label: _("Open Shell Preferences"); 44 | clicked => $on_custom_colors_button_clicked(); 45 | } 46 | } 47 | 48 | Adw.ComboRow variant-row { 49 | title: _("Preset Variant"); 50 | subtitle: _("Select currently applied preset variant"); 51 | } 52 | } 53 | } 54 | 55 | Adw.ActionRow other-options-row { 56 | [prefix] 57 | Button restore_libadw_button { 58 | valign: center; 59 | icon-name: "edit-undo-symbolic"; 60 | sensitive: false; 61 | //tooltip-text: _("Restore Previous Theme"); 62 | tooltip-text: _("Currently unavailable"); 63 | clicked => $on_restore_button_clicked(); 64 | 65 | styles [ 66 | "flat" 67 | ] 68 | } 69 | 70 | [suffix] 71 | Button reset_theme_button { 72 | valign: center; 73 | label: _("Reset Theme"); 74 | tooltip-text: _("Reset applied theme"); 75 | clicked => $on_reset_theme_clicked(); 76 | 77 | styles [ 78 | "destructive-action" 79 | ] 80 | } 81 | } 82 | 83 | -------------------------------------------------------------------------------- /data/ui/theming_empty_group.blp: -------------------------------------------------------------------------------- 1 | using Gtk 4.0; 2 | using Adw 1; 3 | 4 | template $GradienceEmptyThemingGroup : Adw.PreferencesGroup { 5 | title: _("No Theme Engines"); 6 | description: _("Theme Engines extend the functionality of Gradience. They can be enabled in the Preferences."); 7 | 8 | Adw.ActionRow open-preferences { 9 | title: _("Open Preferences to manage Theme Engines"); 10 | 11 | [suffix] 12 | Button open { 13 | valign: center; 14 | label: _("Open Preferences"); 15 | tooltip-text: _("Open Preferences"); 16 | action-name: "app.preferences"; 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /gradience.doap: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | Gradience 9 | Change the look of Adwaita, with ease 10 | 11 | Gradience is a tool for customizing Libadwaita applications and the adw-gtk3 theme. 12 | 13 | 14 | 15 | 16 | 17 | 18 | Python 19 | 20 | 21 | 22 | 0xMRTT 23 | 24 | 0xMRTT 25 | 26 | 27 | 28 | 29 | 30 | Gradience Team 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /gradience/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GradienceTeam/Gradience/f9651091eb80d9c16359598b7030b18c1ebce6c0/gradience/__init__.py -------------------------------------------------------------------------------- /gradience/backend/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GradienceTeam/Gradience/f9651091eb80d9c16359598b7030b18c1ebce6c0/gradience/backend/__init__.py -------------------------------------------------------------------------------- /gradience/backend/constants.py.in: -------------------------------------------------------------------------------- 1 | # constants.py.in 2 | # 3 | # Change the look of Adwaita, with ease 4 | # Copyright (C) 2022 Gradience Team 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program. If not, see . 18 | 19 | rootdir = '/com/github/GradienceTeam/Gradience' 20 | datadir = '@DATA_DIR@' 21 | pkgdatadir = '@PKGDATA_DIR@' 22 | localedir = '@LOCALE_DIR@' 23 | 24 | app_id = '@APP_ID@' 25 | rel_ver = '@RELEASE_VER@' 26 | version = '@VERSION@' 27 | build_type = '@BUILD_TYPE@' 28 | 29 | project_url = '@PROJECT_URL@' 30 | bugtracker_url = '@BUGTRACKER_URL@' 31 | help_url = '@HELP_URL@' 32 | translate_url = '@TRANSLATE_URL@' 33 | -------------------------------------------------------------------------------- /gradience/backend/css_parser.py: -------------------------------------------------------------------------------- 1 | # css_parser.py 2 | # 3 | # Change the look of Adwaita, with ease 4 | # Copyright (C) 2022 Gradience Team 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program. If not, see . 18 | 19 | import re 20 | 21 | from gradience.backend.globals import adw_palette_prefixes 22 | 23 | 24 | # Regular expressions 25 | define_color = re.compile(r"(@define-color .*[^\s])") 26 | not_define_color = re.compile(r"(^(?:(?!@define-color).)*$)") 27 | 28 | def parse_css(path): 29 | css = "" 30 | variables = {} 31 | palette = {} 32 | 33 | for color in adw_palette_prefixes: 34 | palette[color] = {} 35 | 36 | with open(path, "r", encoding="utf-8") as sheet: 37 | for line in sheet: 38 | cdefine_match = re.search(define_color, line) 39 | not_cdefine_match = re.search(not_define_color, line) 40 | if cdefine_match != None: # If @define-color variable declarations were found 41 | palette_part = cdefine_match.__getitem__(1) # Get the second item of the re.Match object 42 | name, color = palette_part.split(" ", 1)[1].split(" ", 1) 43 | if name.startswith(tuple(adw_palette_prefixes)): # Palette colors 44 | palette[name[:-1]][name[-1:]] = color[:-1] 45 | else: # Other color variables 46 | variables[name] = color[:-1] 47 | elif not_cdefine_match != None: # If CSS rules were found 48 | css_part = not_cdefine_match.__getitem__(1) 49 | css += f"{css_part}\n" 50 | 51 | sheet.close() 52 | return variables, palette, css 53 | -------------------------------------------------------------------------------- /gradience/backend/exceptions.py: -------------------------------------------------------------------------------- 1 | # css_parser.py 2 | # 3 | # Change the look of Adwaita, with ease 4 | # Copyright (C) 2023, Gradience Team 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program. If not, see . 18 | 19 | 20 | class GradienceError(Exception): 21 | """ Base class for all other exceptions in Gradience. """ 22 | pass 23 | 24 | 25 | # TODO: Move this module somewhere else later 26 | class UnsupportedShellVersion(GradienceError): 27 | """ Exception raised when the shell version is not supported. """ 28 | pass 29 | -------------------------------------------------------------------------------- /gradience/backend/globals.py: -------------------------------------------------------------------------------- 1 | # globals.py 2 | # 3 | # Change the look of Adwaita, with ease 4 | # Copyright (C) 2022-2023, Gradience Team 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program. If not, see . 18 | 19 | import os 20 | 21 | from gi.repository import Xdp 22 | 23 | from gradience.backend import constants 24 | 25 | 26 | user_config_dir = os.environ.get( 27 | "XDG_CONFIG_HOME", os.environ["HOME"] + "/.config" 28 | ) 29 | 30 | user_data_dir = os.environ.get( 31 | "XDG_DATA_HOME", os.environ["HOME"] + "/.local/share" 32 | ) 33 | 34 | user_cache_dir = os.environ.get( 35 | "XDG_CACHE_HOME", os.environ["HOME"] + "/.cache" 36 | ) 37 | 38 | presets_dir = os.path.join(user_config_dir, "presets") 39 | 40 | user_plugin_dir = os.path.join(user_data_dir, "gradience", "plugins") 41 | system_plugin_dir = os.path.join(constants.pkgdatadir, "plugins") 42 | 43 | preset_repos_github = { 44 | "Official": "https://github.com/GradienceTeam/Community/raw/next/official.json", 45 | "Curated": "https://github.com/GradienceTeam/Community/raw/next/curated.json" 46 | } 47 | 48 | preset_repos_jsdelivr = { 49 | "Official": "https://cdn.jsdelivr.net/gh/GradienceTeam/Community@next/official.json", 50 | "Curated": "https://cdn.jsdelivr.net/gh/GradienceTeam/Community@next/curated.json" 51 | } 52 | 53 | # preset_repos should be dynamically imported depending of user settings 54 | 55 | # Adwaita named UI colors prefixes list 56 | # NOTE: Remember to update this list if new libadwaita version brings up new variables 57 | adw_variables_prefixes = [ 58 | "accent_", 59 | "destructive_", 60 | "success_", 61 | "warning_", 62 | "error_", 63 | "window_", 64 | "view_", 65 | "headerbar_", 66 | "card_", 67 | "dialog_", 68 | "popover_", 69 | "shade_", 70 | "scrollbar_", 71 | "borders" 72 | ] 73 | 74 | # Adwaita named palette colors prefixes list 75 | # NOTE: Remember to update this list if new libadwaita version brings up new variables 76 | adw_palette_prefixes = [ 77 | "blue_", 78 | "green_", 79 | "yellow_", 80 | "orange_", 81 | "red_", 82 | "purple_", 83 | "brown_", 84 | "light_", 85 | "dark_" 86 | ] 87 | 88 | def get_gtk_theme_dir(app_type: str): 89 | if app_type == "gtk4": 90 | theme_dir = os.path.join(user_config_dir, "gtk-4.0") 91 | 92 | if app_type == "gtk3": 93 | theme_dir = os.path.join(user_config_dir, "gtk-3.0") 94 | 95 | return theme_dir 96 | 97 | def is_sandboxed(): 98 | portal = Xdp.Portal() 99 | 100 | is_sandboxed = portal.running_under_sandbox() 101 | 102 | return is_sandboxed 103 | -------------------------------------------------------------------------------- /gradience/backend/meson.build: -------------------------------------------------------------------------------- 1 | backenddir = 'gradience/backend' 2 | 3 | configure_file( 4 | input: 'constants.py.in', 5 | output: 'constants.py', 6 | configuration: configuration_data({ 7 | 'APP_ID': APPLICATION_ID, 8 | 'RELEASE_VER': meson.project_version(), 9 | 'VERSION': meson.project_version() + VERSION_SUFFIX, 10 | 'BUILD_TYPE': get_option('buildtype'), 11 | 'PROJECT_URL': PROJECT_URL, 12 | 'BUGTRACKER_URL': BUGTRACKER_URL, 13 | 'HELP_URL': HELP_URL, 14 | 'TRANSLATE_URL': TRANSLATE_URL, 15 | 'DATA_DIR': conf.get('DATA_DIR'), 16 | 'PKGDATA_DIR': PKGDATA_DIR, 17 | 'LOCALE_DIR': conf.get('LOCALE_DIR'), 18 | }), 19 | install: true, 20 | install_dir: PY_INSTALLDIR.get_install_dir() / backenddir 21 | ) 22 | 23 | subdir('models') 24 | subdir('theming') 25 | subdir('utils') 26 | 27 | gradience_sources = [ 28 | '__init__.py', 29 | 'css_parser.py', 30 | 'flatpak_overrides.py', 31 | 'globals.py', 32 | 'logger.py', 33 | 'preset_downloader.py', 34 | 'exceptions.py' 35 | ] 36 | PY_INSTALLDIR.install_sources(gradience_sources, subdir: backenddir) 37 | -------------------------------------------------------------------------------- /gradience/backend/models/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GradienceTeam/Gradience/f9651091eb80d9c16359598b7030b18c1ebce6c0/gradience/backend/models/__init__.py -------------------------------------------------------------------------------- /gradience/backend/models/meson.build: -------------------------------------------------------------------------------- 1 | modelsdir = 'gradience/backend/models' 2 | 3 | gradience_sources = [ 4 | '__init__.py', 5 | 'preset.py', 6 | 'repo.py' 7 | ] 8 | PY_INSTALLDIR.install_sources(gradience_sources, subdir: modelsdir) 9 | -------------------------------------------------------------------------------- /gradience/backend/models/repo.py: -------------------------------------------------------------------------------- 1 | # repo.py 2 | # 3 | # Change the look of Adwaita, with ease 4 | # Copyright (C) 2022 Gradience Team 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program. If not, see . 18 | 19 | import os 20 | 21 | from gradience.backend.utils.common import to_slug_case 22 | from gradience.backend.globals import presets_dir 23 | from gradience.backend.models.preset import Preset 24 | 25 | 26 | class Repo: 27 | presets = {} 28 | 29 | def __init__(self, name): 30 | self.name = to_slug_case(name) 31 | self.path = os.path.join(presets_dir, name) 32 | self.presets = self.get_presets() 33 | 34 | def get_presets(self): 35 | presets = {} 36 | for preset in os.listdir(self.path): 37 | if preset.endswith(".json"): 38 | preset_path = os.path.join(self.path, preset) 39 | presets[preset[:-5]] = Preset().new_from_path(preset_path) 40 | return presets 41 | -------------------------------------------------------------------------------- /gradience/backend/struct.md: -------------------------------------------------------------------------------- 1 | ## `backend/` directory structure: 2 | 3 | - `models/` - objects containing various types of data, with logic to manipulate them 4 | - `theming/` - theme generation/manipulation specific modules 5 | - `utils/` - general purpose utility modules 6 | -------------------------------------------------------------------------------- /gradience/backend/theming/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GradienceTeam/Gradience/f9651091eb80d9c16359598b7030b18c1ebce6c0/gradience/backend/theming/__init__.py -------------------------------------------------------------------------------- /gradience/backend/theming/meson.build: -------------------------------------------------------------------------------- 1 | themingdir = 'gradience/backend/theming' 2 | 3 | gradience_sources = [ 4 | '__init__.py', 5 | 'monet.py', 6 | 'preset.py', 7 | 'shell.py' 8 | ] 9 | PY_INSTALLDIR.install_sources(gradience_sources, subdir: themingdir) 10 | -------------------------------------------------------------------------------- /gradience/backend/utils/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GradienceTeam/Gradience/f9651091eb80d9c16359598b7030b18c1ebce6c0/gradience/backend/utils/__init__.py -------------------------------------------------------------------------------- /gradience/backend/utils/common.py: -------------------------------------------------------------------------------- 1 | # common.py 2 | # 3 | # Change the look of Adwaita, with ease 4 | # Copyright (C) 2022-2023, Gradience Team 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program. If not, see . 18 | 19 | import re 20 | import os 21 | 22 | from anyascii import anyascii 23 | 24 | from gi.repository import Gio 25 | 26 | 27 | def to_slug_case(non_slug) -> str: 28 | return re.sub(r"[^0-9a-z]+", "-", anyascii(non_slug).lower()).strip("-") 29 | 30 | def extract_version(text, prefix_text=None): 31 | ''' 32 | Extracts version number from a provided text. 33 | 34 | You can also set the prefix_text parameter to reduce searching to 35 | lines with only this text prefixed to the version number. 36 | ''' 37 | if not prefix_text: 38 | version = re.search(r"\s*([0-9.]+)", text) 39 | else: 40 | version = re.search(prefix_text + r"\s*([0-9.]+)", text) 41 | 42 | return version.__getitem__(1) 43 | -------------------------------------------------------------------------------- /gradience/backend/utils/gnome.py: -------------------------------------------------------------------------------- 1 | # shell.py 2 | # 3 | # Change the look of Adwaita, with ease 4 | # Copyright (C) 2023, Gradience Team 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program. If not, see . 18 | 19 | import os 20 | 21 | from gradience.backend.models.preset import Preset 22 | from gradience.backend.utils.subprocess import GradienceSubprocess 23 | from gradience.backend.utils.common import extract_version 24 | 25 | # TODO: Remove this import later (imports from gradience.frontend are not allowed in backend) 26 | from gradience.frontend.schemas.shell_schema import shell_schema 27 | 28 | 29 | # TODO: Return failure if command was not found 30 | def get_shell_version() -> str: 31 | cmd_list = ["gnome-shell", "--version"] 32 | process = GradienceSubprocess() 33 | 34 | completed = process.run(cmd_list, allow_escaping=True) 35 | stdout = process.get_stdout_data(completed, decode=True) 36 | 37 | shell_version = extract_version(stdout, "GNOME Shell") 38 | 39 | return shell_version 40 | 41 | def get_full_shell_version() -> str: 42 | cmd_list = ["gnome-shell", "--version"] 43 | process = GradienceSubprocess() 44 | 45 | completed = process.run(cmd_list, allow_escaping=True) 46 | stdout = process.get_stdout_data(completed, decode=True) 47 | 48 | shell_version = stdout[12:] 49 | 50 | return shell_version 51 | 52 | def is_gnome_available() -> bool: 53 | xdg_current_desktop = os.environ.get("XDG_CURRENT_DESKTOP").lower() 54 | 55 | if "gnome" in xdg_current_desktop: 56 | return True 57 | 58 | return False 59 | 60 | def is_shell_ext_installed(uuid: str, check_enabled: bool = False) -> bool: 61 | """ 62 | Checks if Shell extension with provided UUID from `uuid` parameter 63 | is installed in system. 64 | 65 | `check_enabled` parameter allows for checking if extension is enabled. 66 | """ 67 | 68 | if check_enabled: 69 | cmd_list = ["gnome-extensions", "list", "--enabled"] 70 | else: 71 | cmd_list = ["gnome-extensions", "list"] 72 | 73 | process = GradienceSubprocess() 74 | 75 | completed = process.run(cmd_list, allow_escaping=True) 76 | stdout = process.get_stdout_data(completed, decode=True) 77 | 78 | ext_list = stdout.split("\n") 79 | if ext_list[-1] == "": 80 | ext_list.pop(-1) 81 | 82 | if uuid in ext_list: 83 | return True 84 | 85 | return False 86 | 87 | def get_shell_colors(preset_variables: Preset.variables) -> dict: 88 | shell_colors = {} 89 | 90 | for variable in shell_schema["variables"]: 91 | shell_colors[variable["name"]] = variable["var_name"] 92 | 93 | for shell_key, var_name in shell_colors.items(): 94 | if shell_key == "panel_bg_color": 95 | shell_colors[shell_key] = shell_schema["variables"][5]["default_value"] 96 | continue 97 | shell_colors[shell_key] = preset_variables[var_name] 98 | 99 | return shell_colors 100 | -------------------------------------------------------------------------------- /gradience/backend/utils/meson.build: -------------------------------------------------------------------------------- 1 | utilsdir = 'gradience/backend/utils' 2 | 3 | gradience_sources = [ 4 | '__init__.py', 5 | 'colors.py', 6 | 'common.py', 7 | 'gnome.py', 8 | 'gsettings.py', 9 | 'networking.py', 10 | 'subprocess.py', 11 | 'theming.py' 12 | ] 13 | PY_INSTALLDIR.install_sources(gradience_sources, subdir: utilsdir) 14 | -------------------------------------------------------------------------------- /gradience/backend/utils/networking.py: -------------------------------------------------------------------------------- 1 | # networking.py 2 | # 3 | # Change the look of Adwaita, with ease 4 | # Copyright (C) 2023, Gradience Team 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program. If not, see . 18 | 19 | from urllib.parse import urlparse 20 | 21 | 22 | def get_preset_repos(use_jsdelivr: bool) -> dict: 23 | if use_jsdelivr: 24 | from gradience.backend.globals import preset_repos_jsdelivr 25 | preset_repos = preset_repos_jsdelivr 26 | else: 27 | from gradience.backend.globals import preset_repos_github 28 | preset_repos = preset_repos_github 29 | 30 | return preset_repos 31 | 32 | def github_to_jsdelivr_url(github_url: str) -> str: 33 | """ 34 | Converts Github raw data URL link to JSDelivr CDN link. 35 | """ 36 | 37 | jsdelivr_url = None 38 | 39 | # https://github.com/GradienceTeam/Community/raw/next/official/builder.json => 40 | # https://cdn.jsdelivr.net/gh/GradienceTeam/Community@next/official/builder.json 41 | if "https://github.com" in github_url: 42 | JSDELIVER_FORMAT = "https://cdn.jsdelivr.net/gh/{user}/{repo}@{branch}/{path}" 43 | path = urlparse(github_url).path 44 | user, repo, _, branch, *path = path.strip('/').split('/') 45 | path = "/".join(path) 46 | jsdelivr_url = JSDELIVER_FORMAT.format(user=user, repo=repo, branch=branch, path=path) 47 | 48 | return jsdelivr_url 49 | -------------------------------------------------------------------------------- /gradience/backend/utils/subprocess.py: -------------------------------------------------------------------------------- 1 | # subprocess.py 2 | # 3 | # Change the look of Adwaita, with ease 4 | # Copyright (C) 2022-2023, Gradience Team 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program. If not, see . 18 | 19 | import os 20 | #import signal 21 | 22 | from typing import Union 23 | 24 | import subprocess 25 | from subprocess import SubprocessError, CompletedProcess 26 | 27 | from gradience.backend.logger import Logger 28 | 29 | logging = Logger(logger_name="GradienceSubprocess") 30 | 31 | 32 | # TODO: Check how Dev Toolbox has its backend done fully in async using Gio.Task. 33 | # Example: https://github.com/aleiepure/devtoolbox/blob/main/src/services/gzip_compressor.py 34 | # TODO: Replace subprocess.run() with subprocess.Popen() for more control over subprocesses 35 | class GradienceSubprocess: 36 | """ 37 | Wrapper for Python's `subprocess` module to provide an easy to use 38 | synchronous process spawning and stdout data retrievement with support 39 | for Flatpak sandbox escape. 40 | 41 | Documentation: https://docs.python.org/3/library/subprocess.html 42 | """ 43 | 44 | def __init__(self): 45 | pass 46 | 47 | def run(self, command: list, timeout: int = None, allow_escaping: bool = False) -> CompletedProcess: 48 | """ 49 | Spawns synchronously a new child process (subprocess) using Python's `subprocess` module. 50 | 51 | You can set the `timeout` parameter to kill the process after a 52 | specified amount of seconds. 53 | 54 | You can enable executing commands outside Flatpak sandbox by 55 | enabling `allow_escaping` parameter. 56 | """ 57 | 58 | if allow_escaping and os.environ.get('FLATPAK_ID'): 59 | command = ['flatpak-spawn', '--host'] + command 60 | 61 | logging.debug(f"Spawning: {command}") 62 | 63 | try: 64 | process = subprocess.run(command, check=True, 65 | capture_output=True, timeout=timeout) 66 | except SubprocessError: 67 | raise 68 | except FileNotFoundError: 69 | raise 70 | 71 | return process 72 | 73 | def get_stdout_data(self, process: CompletedProcess, decode: bool = False) -> Union[str, bytes]: 74 | """ 75 | Returns a data retrieved from stdout stream. 76 | 77 | Default behavior returns a full data collection in bytes array. 78 | Setting ``decode`` parameter to True will automatically decode data to string object. 79 | """ 80 | 81 | if decode: 82 | stdout_string = process.stdout.decode() 83 | return stdout_string 84 | 85 | return process.stdout 86 | 87 | '''def stop(self, process: CompletedProcess) -> None: 88 | logging.debug(f"Terminating process, ID {process.get_identifier()}") 89 | process.send_signal(signal.SIGTERM) 90 | 91 | def kill(self, process: CompletedProcess) -> None: 92 | logging.debug(f"Killing process, ID {process.get_identifier()}") 93 | self.cancel_read() 94 | process.send_signal(signal.SIGKILL)''' 95 | -------------------------------------------------------------------------------- /gradience/backend/utils/theming.py: -------------------------------------------------------------------------------- 1 | # theming.py 2 | # 3 | # Change the look of Adwaita, with ease 4 | # Copyright (C) 2023, Gradience Team 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program. If not, see . 18 | 19 | from gradience.backend.models.preset import Preset 20 | 21 | 22 | def generate_gtk_css(app_type: str, preset: Preset) -> str: 23 | variables = preset.variables 24 | palette = preset.palette 25 | custom_css = preset.custom_css 26 | 27 | theming_warning = """/* 28 | Generated with Gradience 29 | 30 | Issues caused by theming should be reported to Gradience repository, and not to upstream 31 | 32 | https://github.com/GradienceTeam/Gradience 33 | */ 34 | 35 | """ 36 | 37 | gtk_css = "" 38 | 39 | for key in variables.keys(): 40 | gtk_css += f"@define-color {key} {variables[key]};\n" 41 | 42 | for prefix_key in palette.keys(): 43 | for key in palette[prefix_key].keys(): 44 | gtk_css += f"@define-color {prefix_key + key} {palette[prefix_key][key]};\n" 45 | 46 | gtk_css += custom_css.get(app_type, "") 47 | 48 | gtk_css += "\n.navigation-sidebar {\nbackground-color: " 49 | gtk_css += variables["window_bg_color"] 50 | gtk_css += ";\n}" 51 | 52 | final_css = theming_warning + gtk_css 53 | 54 | return final_css 55 | -------------------------------------------------------------------------------- /gradience/frontend/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GradienceTeam/Gradience/f9651091eb80d9c16359598b7030b18c1ebce6c0/gradience/frontend/__init__.py -------------------------------------------------------------------------------- /gradience/frontend/cli/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GradienceTeam/Gradience/f9651091eb80d9c16359598b7030b18c1ebce6c0/gradience/frontend/cli/__init__.py -------------------------------------------------------------------------------- /gradience/frontend/cli/meson.build: -------------------------------------------------------------------------------- 1 | clidir = 'gradience/frontend/cli' 2 | 3 | configure_file( 4 | input: 'cli.in', 5 | output: 'gradience-cli', 6 | configuration: conf, 7 | install_dir: get_option('bindir') 8 | ) 9 | 10 | if get_option('buildtype') == 'debug' 11 | configure_file( 12 | input: 'cli.in', 13 | output: 'local-gradience-cli', 14 | configuration: local_conf, 15 | install_dir: join_paths(meson.project_build_root(), 'gradience', 'frontend') 16 | ) 17 | endif 18 | 19 | gradience_sources = [ 20 | '__init__.py' 21 | ] 22 | PY_INSTALLDIR.install_sources(gradience_sources, subdir: clidir) 23 | -------------------------------------------------------------------------------- /gradience/frontend/dialogs/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GradienceTeam/Gradience/f9651091eb80d9c16359598b7030b18c1ebce6c0/gradience/frontend/dialogs/__init__.py -------------------------------------------------------------------------------- /gradience/frontend/dialogs/app_type_dialog.py: -------------------------------------------------------------------------------- 1 | # app_type_dialog.py 2 | # 3 | # Change the look of Adwaita, with ease 4 | # Copyright (C) 2022-2023, Gradience Team 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program. If not, see . 18 | 19 | from gi.repository import Gtk, Adw 20 | 21 | from gradience.backend.constants import rootdir 22 | 23 | 24 | @Gtk.Template(resource_path=f"{rootdir}/ui/app_type_dialog.ui") 25 | class GradienceAppTypeDialog(Adw.MessageDialog): 26 | __gtype_name__ = "GradienceAppTypeDialog" 27 | 28 | gtk4_app_type = Gtk.Template.Child("gtk4-app-type") 29 | gtk3_app_type = Gtk.Template.Child("gtk3-app-type") 30 | 31 | def __init__(self, parent, heading, body, ok_res_name, ok_res_label, ok_res_appearance, **kwargs): 32 | super().__init__(**kwargs) 33 | 34 | self.parent = parent 35 | self.app = self.parent.get_application() 36 | 37 | if isinstance(self.parent, Gtk.Window): 38 | self.win = self.parent 39 | else: 40 | self.win = self.app.get_active_window() 41 | 42 | self.set_transient_for(self.win) 43 | 44 | self.set_heading(heading) 45 | self.set_body(body) 46 | 47 | self.add_response("cancel", _("_Cancel")) 48 | self.add_response(ok_res_name, ok_res_label) 49 | self.set_response_appearance(ok_res_name, ok_res_appearance) 50 | self.set_default_response("cancel") 51 | self.set_close_response("cancel") 52 | 53 | def get_app_types(self): 54 | return { 55 | "gtk4": self.gtk4_app_type.get_active(), 56 | "gtk3": self.gtk3_app_type.get_active() 57 | } 58 | -------------------------------------------------------------------------------- /gradience/frontend/dialogs/meson.build: -------------------------------------------------------------------------------- 1 | dialogsdir = 'gradience/frontend/dialogs' 2 | 3 | gradience_sources = [ 4 | '__init__.py', 5 | 'app_type_dialog.py', 6 | 'save_dialog.py', 7 | 'unsupported_shell_dialog.py' 8 | ] 9 | PY_INSTALLDIR.install_sources(gradience_sources, subdir: dialogsdir) 10 | -------------------------------------------------------------------------------- /gradience/frontend/dialogs/save_dialog.py: -------------------------------------------------------------------------------- 1 | # save_dialog.py 2 | # 3 | # Change the look of Adwaita, with ease 4 | # Copyright (C) 2023, Gradience Team 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program. If not, see . 18 | 19 | from gi.repository import Gtk, Adw 20 | 21 | from gradience.backend.constants import rootdir 22 | 23 | 24 | # TODO: Make this dialog async when Libadwaita 1.3 becomes available \ 25 | # https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/method.MessageDialog.choose.html 26 | @Gtk.Template(resource_path=f"{rootdir}/ui/save_dialog.ui") 27 | class GradienceSaveDialog(Adw.MessageDialog): 28 | __gtype_name__ = "GradienceSaveDialog" 29 | 30 | preset_entry = Gtk.Template.Child("preset-entry") 31 | 32 | def __init__(self, parent, heading=None, body=None, path=None, discard=False, **kwargs): 33 | super().__init__(**kwargs) 34 | 35 | self.parent = parent 36 | self.app = self.parent.get_application() 37 | 38 | self.body = _( 39 | "Saving preset to \n {0}. \n If that preset already " 40 | "exists, it will be overwritten." 41 | ) 42 | 43 | if isinstance(self.parent, Gtk.Window): 44 | self.win = self.parent 45 | else: 46 | self.win = self.app.get_active_window() 47 | 48 | self.set_transient_for(self.win) 49 | 50 | if heading: 51 | self.heading = heading 52 | self.set_heading(self.heading) 53 | 54 | if not body and path: 55 | self.set_body(self.body.format(path)) 56 | elif body: 57 | self.body = body 58 | self.set_body(self.body) 59 | elif not body and not path: 60 | raise AttributeError("DEV FAULT: You need to either specify 'body' or 'path' parameter") 61 | 62 | self.add_response("cancel", _("_Cancel")) 63 | 64 | if discard: 65 | self.add_response("discard", _("Discard")) 66 | self.set_response_appearance( 67 | "discard", Adw.ResponseAppearance.DESTRUCTIVE 68 | ) 69 | 70 | self.add_response("save", _("_Save")) 71 | self.set_default_response("cancel") 72 | self.set_close_response("cancel") 73 | 74 | self.set_response_appearance( 75 | "save", Adw.ResponseAppearance.SUGGESTED 76 | ) 77 | 78 | -------------------------------------------------------------------------------- /gradience/frontend/dialogs/unsupported_shell_dialog.py: -------------------------------------------------------------------------------- 1 | # unsupported_shell_version.py 2 | # 3 | # Change the look of Adwaita, with ease 4 | # Copyright (C) 2022-2023, Gradience Team 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program. If not, see . 18 | 19 | from gi.repository import Gtk, Adw 20 | 21 | from gradience.backend.constants import rootdir 22 | from gradience.backend.utils.gnome import get_full_shell_version 23 | 24 | class GradienceUnsupportedShellDialog(Adw.MessageDialog): 25 | __gtype_name__ = "GradienceUnsupportedShellDialog" 26 | 27 | def __init__(self, parent, **kwargs): 28 | super().__init__(**kwargs) 29 | 30 | self.parent = parent 31 | self.app = self.parent.get_application() 32 | 33 | if isinstance(self.parent, Gtk.Window): 34 | self.win = self.parent 35 | else: 36 | self.win = self.app.get_active_window() 37 | 38 | self.set_transient_for(self.win) 39 | 40 | self.set_heading(_(f"Unsupported Shell Version ({get_full_shell_version()})")) 41 | self.set_body(_("The Shell version you are using is not supported by Gradience. Please upgrade to a newer version of GNOME.")) 42 | 43 | self.add_response("ok", _("OK")) 44 | self.set_default_response("ok") 45 | self.set_close_response("ok") 46 | -------------------------------------------------------------------------------- /gradience/frontend/gradience.in: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # gradience.in 4 | # 5 | # Change the look of Adwaita, with ease 6 | # Copyright (C) 2022 Gradience Team 7 | # 8 | # This program is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU General Public License as published by 10 | # the Free Software Foundation, either version 3 of the License, or 11 | # (at your option) any later version. 12 | # 13 | # This program is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU General Public License 19 | # along with this program. If not, see . 20 | 21 | import os 22 | import sys 23 | import signal 24 | import locale 25 | import shutil 26 | import gettext 27 | 28 | is_local = @local_build@ 29 | 30 | if is_local: 31 | # In the local use case, use gradience module from the sourcetree 32 | sys.path.insert(1, '@PYTHON@') 33 | 34 | # In the local use case the installed schemas go in /data 35 | os.environ["XDG_DATA_DIRS"] = '@SCHEMAS_DIR@:' + os.environ.get("XDG_DATA_DIRS", "") 36 | 37 | shutil.copyfile( 38 | os.path.join('@BUILD_DIR@', "gradience/backend", "constants.py"), 39 | os.path.join('@SOURCE_DIR@', "gradience/backend", "constants.py") 40 | ) 41 | 42 | pkgdatadir = '@PKGDATA_DIR@' 43 | localedir = '@LOCALE_DIR@' 44 | 45 | sys.dont_write_bytecode = True 46 | 47 | signal.signal(signal.SIGINT, signal.SIG_DFL) 48 | gettext.install('gradience', localedir) 49 | 50 | locale.bindtextdomain('gradience', localedir) 51 | locale.textdomain('gradience') 52 | 53 | 54 | if __name__ == '__main__': 55 | import gi 56 | 57 | gi.require_version('Gtk', '4.0') 58 | gi.require_version('Adw', '1') 59 | gi.require_version('Xdp', '1.0') 60 | gi.require_version('XdpGtk4', '1.0') 61 | gi.require_version('Soup', '3.0') 62 | 63 | from gi.repository import Gio 64 | resource = Gio.Resource.load( 65 | os.path.join(pkgdatadir, 'gradience.gresource')) 66 | Gio.Resource._register(resource) 67 | 68 | sys.path.insert(1, "/usr/local/lib/python3.10/site-packages") 69 | 70 | from gradience.frontend import main 71 | sys.exit(main.main()) 72 | -------------------------------------------------------------------------------- /gradience/frontend/meson.build: -------------------------------------------------------------------------------- 1 | frontenddir = 'gradience/frontend' 2 | 3 | configure_file( 4 | input: 'gradience.in', 5 | output: 'gradience', 6 | configuration: conf, 7 | install_dir: get_option('bindir') 8 | ) 9 | 10 | if get_option('buildtype') == 'debug' 11 | configure_file( 12 | input: 'gradience.in', 13 | output: 'local-gradience', 14 | configuration: local_conf 15 | ) 16 | 17 | launcher = join_paths(meson.project_build_root(), moduledir, 'frontend', 'local-' + meson.project_name()) 18 | 19 | run_target('run', 20 | command: [launcher] 21 | ) 22 | endif 23 | 24 | subdir('cli') 25 | subdir('dialogs') 26 | subdir('schemas') 27 | subdir('utils') 28 | subdir('views') 29 | subdir('widgets') 30 | 31 | gradience_sources = [ 32 | '__init__.py', 33 | 'main.py' 34 | ] 35 | PY_INSTALLDIR.install_sources(gradience_sources, subdir: frontenddir) 36 | -------------------------------------------------------------------------------- /gradience/frontend/schemas/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GradienceTeam/Gradience/f9651091eb80d9c16359598b7030b18c1ebce6c0/gradience/frontend/schemas/__init__.py -------------------------------------------------------------------------------- /gradience/frontend/schemas/meson.build: -------------------------------------------------------------------------------- 1 | schemasdir = 'gradience/frontend/schemas' 2 | 3 | gradience_sources = [ 4 | '__init__.py', 5 | 'preset_schema.py', 6 | 'shell_schema.py' 7 | ] 8 | PY_INSTALLDIR.install_sources(gradience_sources, subdir: schemasdir) 9 | -------------------------------------------------------------------------------- /gradience/frontend/schemas/shell_schema.py: -------------------------------------------------------------------------------- 1 | # shell_schema.py 2 | # 3 | # Change the look of Adwaita, with ease 4 | # Copyright (C) 2023, Gradience Team 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program. If not, see . 18 | 19 | shell_schema = { 20 | "variables": [ 21 | { 22 | "name": "bg_color", 23 | "var_name": "window_bg_color", 24 | "title": _("Base Background Color") 25 | }, 26 | { 27 | "name": "fg_color", 28 | "var_name": "window_fg_color", 29 | "title": _("Base Foreground Color") 30 | }, 31 | { 32 | "name": "system_bg_color", 33 | "var_name": "window_bg_color", 34 | "title": _("Overview Background Color") 35 | }, 36 | { 37 | "name": "selected_bg_color", 38 | "var_name": "accent_bg_color", 39 | "title": _("Accent Background Color") 40 | }, 41 | { 42 | "name": "selected_fg_color", 43 | "var_name": "window_fg_color", 44 | "title": _("Accent Foreground Color") 45 | }, 46 | # TODO: Fix panel background color injection code 47 | #{ 48 | # "name": "panel_bg_color", 49 | # "var_name": "panel_bg_color", 50 | # "title": _("Panel Background Color"), 51 | # "default_value": "#000" 52 | #}, 53 | #{ 54 | # "name": "osd_bg_color", 55 | # "var_name": "window_bg_color", 56 | # "title": _("OSD Background Color") 57 | #}, 58 | { 59 | "name": "osd_fg_color", 60 | "var_name": "window_fg_color", 61 | "title": _("OSD Foreground Color") 62 | } 63 | ] 64 | } 65 | -------------------------------------------------------------------------------- /gradience/frontend/struct.md: -------------------------------------------------------------------------------- 1 | ## `frontend/` directory structure: 2 | 3 | - `cli/` - frontend command-line based interface for Gradience's backend functions 4 | - `dialogs/` - message boxes and simple popup windows 5 | - `schemas/` - color view schemas, mostly used to dynamically construct views with GradienceOptionRow widget 6 | - `utils/` - general purpose utility modules and helpers for UI related stuff 7 | - `views/` - more extensive widgets (eg. widget groups, lists) and GTK window views 8 | - `widgets/` - simple custom (eg. custom Adw.ActionRow) widgets 9 | -------------------------------------------------------------------------------- /gradience/frontend/utils/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GradienceTeam/Gradience/f9651091eb80d9c16359598b7030b18c1ebce6c0/gradience/frontend/utils/__init__.py -------------------------------------------------------------------------------- /gradience/frontend/utils/actions.py: -------------------------------------------------------------------------------- 1 | # actions.py 2 | # 3 | # Change the look of Adwaita, with ease 4 | # Copyright (C) 2023, Gradience Team 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program. If not, see . 18 | 19 | from gi.repository import Gio 20 | 21 | 22 | class ActionHelpers: 23 | def __init__(self, parent): 24 | self.parent = parent 25 | 26 | def create_action(self, name, callback, shortcuts=None): 27 | """Add an application action. 28 | 29 | Args: 30 | name: the name of the action 31 | callback: the function to be called when the action is 32 | activated 33 | shortcuts: an optional list of accelerators 34 | """ 35 | 36 | action = Gio.SimpleAction.new(name, None) 37 | action.connect("activate", callback) 38 | 39 | self.parent.add_action(action) 40 | 41 | if shortcuts: 42 | self.parent.set_accels_for_action(f"app.{name}", shortcuts) 43 | 44 | def create_stateful_action(self, name, parameter_type, initial_state, callback, shortcuts=None): 45 | """Add a stateful application action.""" 46 | 47 | action = Gio.SimpleAction.new_stateful( 48 | name, parameter_type, initial_state) 49 | action.connect("activate", callback) 50 | 51 | self.parent.add_action(action) 52 | 53 | if shortcuts: 54 | self.parent.set_accels_for_action(f"app.{name}", shortcuts) 55 | -------------------------------------------------------------------------------- /gradience/frontend/utils/meson.build: -------------------------------------------------------------------------------- 1 | utilsdir = 'gradience/frontend/utils' 2 | 3 | gradience_sources = [ 4 | '__init__.py', 5 | 'actions.py', 6 | 'run_async.py' 7 | ] 8 | PY_INSTALLDIR.install_sources(gradience_sources, subdir: utilsdir) 9 | -------------------------------------------------------------------------------- /gradience/frontend/utils/run_async.py: -------------------------------------------------------------------------------- 1 | # run_async.py 2 | # 3 | # Change the look of Adwaita, with ease 4 | # Copyright (C) 2022 Gradience Team 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program. If not, see . 18 | 19 | import sys 20 | import threading 21 | import traceback 22 | 23 | from gi.repository import GLib 24 | 25 | from gradience.backend.logger import Logger 26 | 27 | logging = Logger() 28 | 29 | 30 | class RunAsync(threading.Thread): 31 | def __init__(self, task_func, callback=None, *args, **kwargs): 32 | self.source_id = None 33 | if threading.current_thread() is not threading.main_thread(): 34 | raise AssertionError 35 | 36 | super(RunAsync, self).__init__( 37 | target=self.target, args=args, kwargs=kwargs) 38 | 39 | self.task_func = task_func 40 | 41 | self.callback = callback if callback else lambda r, e: None 42 | self.daemon = kwargs.pop("daemon", True) 43 | 44 | self.start() 45 | 46 | def target(self, *args, **kwargs): 47 | result = None 48 | error = None 49 | 50 | logging.debug(f"Running async job [{self.task_func}].") 51 | 52 | try: 53 | result = self.task_func(*args, **kwargs) 54 | except Exception as e: 55 | logging.error(f"Error while running async job: {self.task_func}", exc=e) 56 | 57 | error = exception 58 | _ex_type, _ex_value, trace = sys.exc_info() 59 | traceback.print_tb(trace) 60 | traceback_info = "\n".join(traceback.format_tb(trace)) 61 | 62 | logging.error([str(exception), traceback_info]) 63 | self.source_id = GLib.idle_add(self.callback, result, error) 64 | return self.source_id 65 | -------------------------------------------------------------------------------- /gradience/frontend/views/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GradienceTeam/Gradience/f9651091eb80d9c16359598b7030b18c1ebce6c0/gradience/frontend/views/__init__.py -------------------------------------------------------------------------------- /gradience/frontend/views/about_window.py: -------------------------------------------------------------------------------- 1 | # about_window.py 2 | # 3 | # Change the look of Adwaita, with ease 4 | # Copyright (C) 2023, Gradience Team 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program. If not, see . 18 | 19 | from gi.repository import Gtk, Adw 20 | 21 | from gradience.backend import constants 22 | 23 | 24 | # TRANSLATORS: This is a place to put your credits (formats: 25 | # "Name https://example.com" or "Name ", 26 | # no quotes) and is not meant to be translated literally. 27 | translator_credits = _("translator-credits") 28 | 29 | class GradienceAboutWindow: 30 | def __init__(self, parent): 31 | self.parent = parent 32 | self.app = self.parent.get_application() 33 | 34 | self.setup() 35 | 36 | def setup(self): 37 | self.about_window = Adw.AboutWindow( 38 | application_name="Gradience", 39 | transient_for=self.app.get_active_window(), 40 | application_icon=constants.app_id, 41 | developer_name=_("Gradience Team"), 42 | website=constants.project_url, 43 | support_url=constants.help_url, 44 | issue_url=constants.bugtracker_url, 45 | developers=[ 46 | "0xMRTT https://github.com/0xMRTT", 47 | "Artyom Fomin https://github.com/ArtyIF", 48 | "Verantor https://github.com/Verantor", 49 | "tfuxu https://github.com/tfuxu", 50 | "u1F98E https://github.com/u1f98e" 51 | ], 52 | designers=[ 53 | "David Lapshin https://github.com/daudix-UFO" 54 | ], 55 | translator_credits=_(translator_credits), 56 | copyright=_("Copyright © 2022-2023 Gradience Team"), 57 | license_type=Gtk.License.GPL_3_0, 58 | version=constants.version, 59 | release_notes_version=constants.rel_ver, 60 | ) 61 | 62 | self.about_window.add_credit_section( 63 | _("Plugins by"), 64 | [ 65 | _("Contributors on GitHub https://github.com/GradienceTeam/Plugins/graphs/contributors") 66 | ] 67 | ) 68 | self.about_window.add_credit_section( 69 | _("Presets by"), 70 | [ 71 | _("Contributors on GitHub https://github.com/GradienceTeam/Community/graphs/contributors") 72 | ] 73 | ) 74 | 75 | def show_about(self): 76 | self.about_window.present() 77 | -------------------------------------------------------------------------------- /gradience/frontend/views/meson.build: -------------------------------------------------------------------------------- 1 | viewsdir = 'gradience/frontend/views' 2 | 3 | gradience_sources = [ 4 | '__init__.py', 5 | 'about_window.py', 6 | 'main_window.py', 7 | 'no_plugin_window.py', 8 | 'plugins_list.py', 9 | 'preferences_window.py', 10 | 'presets_manager_window.py', 11 | 'share_window.py', 12 | 'shell_prefs_window.py', 13 | 'welcome_window.py' 14 | ] 15 | PY_INSTALLDIR.install_sources(gradience_sources, subdir: viewsdir) 16 | -------------------------------------------------------------------------------- /gradience/frontend/views/no_plugin_window.py: -------------------------------------------------------------------------------- 1 | # no_plugin_window.py 2 | # 3 | # Change the look of Adwaita, with ease 4 | # Copyright (C) 2022-2023, Gradience Team 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program. If not, see . 18 | 19 | from gi.repository import Gtk, Adw 20 | 21 | from gradience.backend.constants import rootdir 22 | 23 | 24 | @Gtk.Template(resource_path=f"{rootdir}/ui/no_plugin_window.ui") 25 | class GradienceNoPluginPrefWindow(Adw.PreferencesWindow): 26 | __gtype_name__ = "GradienceNoPluginPrefWindow" 27 | 28 | def __init__(self, **kwargs): 29 | super().__init__(**kwargs) 30 | -------------------------------------------------------------------------------- /gradience/frontend/views/shell_prefs_window.py: -------------------------------------------------------------------------------- 1 | # shell_prefs_window.py 2 | # 3 | # Change the look of Adwaita, with ease 4 | # Copyright (C) 2023, Gradience Team 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program. If not, see . 18 | 19 | from gi.repository import Gtk, Adw 20 | 21 | from gradience.backend.utils.colors import rgb_to_hash 22 | from gradience.backend.constants import rootdir 23 | 24 | from gradience.frontend.widgets.option_row import GradienceOptionRow 25 | from gradience.frontend.schemas.shell_schema import shell_schema 26 | 27 | from gradience.backend.logger import Logger 28 | 29 | logging = Logger() 30 | 31 | 32 | @Gtk.Template(resource_path=f"{rootdir}/ui/shell_prefs_window.ui") 33 | class GradienceShellPrefsWindow(Adw.PreferencesWindow): 34 | __gtype_name__ = "GradienceShellPrefsWindow" 35 | 36 | custom_colors_group = Gtk.Template.Child("custom-colors-group") 37 | 38 | def __init__(self, parent, shell_colors: dict, **kwargs): 39 | super().__init__(**kwargs) 40 | 41 | self.shell_colors = shell_colors 42 | 43 | self.parent = parent 44 | self.settings = parent.settings 45 | self.app = self.parent.get_application() 46 | 47 | self.set_transient_for(self.app.get_active_window()) 48 | 49 | self.setup() 50 | 51 | def setup(self): 52 | for variable in shell_schema["variables"]: 53 | pref_variable = GradienceOptionRow( 54 | variable["name"], 55 | variable["title"] 56 | #variable.get("explanation") 57 | ) 58 | self.custom_colors_group.add(pref_variable) 59 | 60 | pref_variable.color_value.connect("color-set", self.on_color_value_changed, pref_variable) 61 | pref_variable.text_value.connect("changed", self.on_text_value_changed, pref_variable) 62 | 63 | self.set_colors(pref_variable, variable) 64 | 65 | def set_colors(self, widget, variable): 66 | if len(self.shell_colors) != len(shell_schema["variables"]): 67 | try: 68 | self.shell_colors[variable["name"]] = variable["default_value"] 69 | except KeyError: 70 | try: 71 | self.shell_colors[variable["name"]] = self.app.variables[variable["var_name"]] 72 | except KeyError: 73 | raise 74 | finally: 75 | widget.update_value(self.shell_colors[variable["name"]]) 76 | else: 77 | widget.update_value(self.shell_colors[variable["name"]]) 78 | 79 | def on_color_value_changed(self, widget, parent, *_args): 80 | color_name = parent.props.name 81 | color_value = widget.get_rgba().to_string() 82 | 83 | if color_value.startswith("rgb") or color_value.startswith("rgba"): 84 | color_hex, alpha = rgb_to_hash(color_value) 85 | if not alpha: 86 | color_value = color_hex 87 | 88 | self.shell_colors[color_name] = color_value 89 | 90 | def on_text_value_changed(self, widget, parent, *_args): 91 | color_name = parent.props.name 92 | color_value = widget.get_text() 93 | 94 | self.shell_colors[color_name] = color_value 95 | -------------------------------------------------------------------------------- /gradience/frontend/widgets/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GradienceTeam/Gradience/f9651091eb80d9c16359598b7030b18c1ebce6c0/gradience/frontend/widgets/__init__.py -------------------------------------------------------------------------------- /gradience/frontend/widgets/builtin_preset_row.py: -------------------------------------------------------------------------------- 1 | # builtin_preset_row.py 2 | # 3 | # Change the look of Adwaita, with ease 4 | # Copyright (C) 2022-2023 Gradience Team 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program. If not, see . 18 | 19 | from gi.repository import Gtk, Adw 20 | 21 | from gradience.backend.utils.common import to_slug_case 22 | from gradience.backend.constants import rootdir 23 | 24 | from gradience.backend.logger import Logger 25 | 26 | logging = Logger() 27 | 28 | 29 | @Gtk.Template(resource_path=f"{rootdir}/ui/builtin_preset_row.ui") 30 | class GradienceBuiltinPresetRow(Adw.ActionRow): 31 | __gtype_name__ = "GradienceBuiltinPresetRow" 32 | 33 | def __init__(self, name, toast_overlay, author="", **kwargs): 34 | super().__init__(**kwargs) 35 | 36 | self.name = name 37 | 38 | self.set_name(name) 39 | self.set_title(name) 40 | 41 | self.app = Gtk.Application.get_default() 42 | 43 | self.toast_overlay = toast_overlay 44 | 45 | def show_unsaved_dialog(self, *_args): 46 | dialog, preset_entry = self.app.construct_unsaved_dialog() 47 | 48 | def on_unsaved_dialog_response(_widget, response, preset_entry): 49 | if response == "save": 50 | self.app.preset.save_to_file(preset_entry.get_text(), self.app.plugins_list) 51 | self.app.clear_dirty() 52 | self.app.load_preset_from_resource( 53 | f"{rootdir}/presets/" + to_slug_case(self.name) + ".json" 54 | ) 55 | elif response == "discard": 56 | self.app.clear_dirty() 57 | self.app.load_preset_from_resource( 58 | f"{rootdir}/presets/" + to_slug_case(self.name) + ".json" 59 | ) 60 | 61 | dialog.connect("response", on_unsaved_dialog_response, preset_entry) 62 | 63 | dialog.present() 64 | 65 | @Gtk.Template.Callback() 66 | def on_apply_button_clicked(self, *_args): 67 | logging.debug("apply") 68 | 69 | if self.app.is_dirty: 70 | self.show_unsaved_dialog() 71 | else: 72 | self.app.load_preset_from_resource( 73 | f"{rootdir}/presets/" + to_slug_case(self.name) + ".json" 74 | ) 75 | -------------------------------------------------------------------------------- /gradience/frontend/widgets/custom_css_group.py: -------------------------------------------------------------------------------- 1 | # custom_css_group.py 2 | # 3 | # Change the look of Adwaita, with ease 4 | # Copyright (C) 2022 Gradience Team 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program. If not, see . 18 | 19 | from gi.repository import Gtk, Adw 20 | 21 | from gradience.backend.constants import rootdir 22 | 23 | from gradience.backend.logger import Logger 24 | 25 | logging = Logger() 26 | 27 | 28 | @Gtk.Template(resource_path=f"{rootdir}/ui/custom_css_group.ui") 29 | class GradienceCustomCSSGroup(Adw.PreferencesGroup): 30 | __gtype_name__ = "GradienceCustomCSSGroup" 31 | 32 | app_type_dropdown = Gtk.Template.Child("app_type_dropdown") 33 | custom_css_text_view = Gtk.Template.Child("custom_css_text_view") 34 | 35 | def __init__(self, parent, **kwargs): 36 | super().__init__(**kwargs) 37 | 38 | self.parent = parent 39 | self.app = self.parent.get_application() 40 | 41 | self.custom_css = {} 42 | 43 | def load_custom_css(self, custom_css): 44 | self.custom_css = custom_css 45 | 46 | self.custom_css_text_view.get_buffer().set_text( 47 | list(self.custom_css.values())[ 48 | self.app_type_dropdown.get_selected()] 49 | ) 50 | 51 | def reset_buffer(self): 52 | self.app.update_custom_css_text("gtk3", "") 53 | self.app.update_custom_css_text("gtk4", "") 54 | 55 | self.custom_css_text_view.get_buffer().set_text("") 56 | 57 | @Gtk.Template.Callback() 58 | def on_custom_css_changed(self, buffer): 59 | self.app.mark_as_dirty() 60 | self.app.update_custom_css_text( 61 | list(self.custom_css.keys())[ 62 | self.app_type_dropdown.get_selected()], 63 | buffer.props.text 64 | ) 65 | 66 | @Gtk.Template.Callback() 67 | def on_dropdown_notify(self, _unused, pspec): 68 | if pspec.name == "selected": 69 | logging.debug(f"Custom CSS values: {self.custom_css.values()}") 70 | logging.debug(f"Selected app type in dropdown: {self.app_type_dropdown.get_selected()}") 71 | self.custom_css_text_view.get_buffer().set_text( 72 | list(self.custom_css.values())[ 73 | self.app_type_dropdown.get_selected()] 74 | ) 75 | -------------------------------------------------------------------------------- /gradience/frontend/widgets/error_list_row.py: -------------------------------------------------------------------------------- 1 | # error_list_row.py 2 | # 3 | # Change the look of Adwaita, with ease 4 | # Copyright (C) 2022 Adwaita Manager Team 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program. If not, see . 18 | 19 | from gi.repository import Gtk 20 | 21 | from gradience.backend.constants import rootdir 22 | 23 | 24 | @Gtk.Template(resource_path=f"{rootdir}/ui/error_list_row.ui") 25 | class GradienceErrorListRow(Gtk.ListBoxRow): 26 | __gtype_name__ = "GradienceErrorListRow" 27 | 28 | error_label = Gtk.Template.Child("error-label") 29 | element_label = Gtk.Template.Child("element-label") 30 | line_label = Gtk.Template.Child("line-label") 31 | 32 | def __init__(self, error, element, line, **kwargs): 33 | super().__init__(**kwargs) 34 | 35 | self.error_label.set_label(error) 36 | self.element_label.set_label(element) 37 | self.line_label.set_label(line) 38 | -------------------------------------------------------------------------------- /gradience/frontend/widgets/explore_preset_row.py: -------------------------------------------------------------------------------- 1 | # explore_preset_row.py 2 | # 3 | # Change the look of Adwaita, with ease 4 | # Copyright (C) 2022 Gradience Team 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program. If not, see . 18 | 19 | import os 20 | import json 21 | 22 | from gi.repository import GLib, Gtk, Adw 23 | 24 | from gradience.backend.utils.common import to_slug_case 25 | from gradience.backend.preset_downloader import PresetDownloader 26 | from gradience.backend.constants import rootdir 27 | 28 | from gradience.backend.logger import Logger 29 | 30 | logging = Logger() 31 | 32 | 33 | @Gtk.Template(resource_path=f"{rootdir}/ui/explore_preset_row.ui") 34 | class GradienceExplorePresetRow(Adw.ActionRow): 35 | __gtype_name__ = "GradienceExplorePresetRow" 36 | 37 | apply_button = Gtk.Template.Child("apply_button") 38 | download_button = Gtk.Template.Child("download_button") 39 | # badge = Gtk.Template.Child("badge") 40 | 41 | def __init__(self, name, url, win, repo_name, badge, **kwargs): 42 | super().__init__(**kwargs) 43 | 44 | self.name = name 45 | 46 | self.prefix = to_slug_case(repo_name) 47 | 48 | self.set_name(name) 49 | self.set_title(name) 50 | self.set_subtitle(repo_name) 51 | 52 | # self.badge.set_label(repo_name) 53 | # self.badge.get_style_context().add_class(f"badge-{badge}") 54 | 55 | self.app = Gtk.Application.get_default() 56 | self.win = win 57 | self.toast_overlay = self.win.toast_overlay 58 | 59 | self.url = url 60 | 61 | @Gtk.Template.Callback() 62 | def on_apply_button_clicked(self, *_args): 63 | try: 64 | PresetDownloader().download_preset(to_slug_case(self.name), self.prefix, self.url) 65 | except (GLib.GError, json.JSONDecodeError, OSError): 66 | logging.error("An error occurred while trying to download a preset.") 67 | self.toast_overlay.add_toast( 68 | Adw.Toast(title=_("Preset could not be downloaded")) 69 | ) 70 | else: 71 | self.app.load_preset_from_file( 72 | os.path.join( 73 | os.environ.get("XDG_CONFIG_HOME", 74 | os.environ["HOME"] + "/.config"), 75 | "presets", 76 | self.prefix, 77 | to_slug_case(self.name) + ".json", 78 | ) 79 | ) 80 | 81 | self.toast_overlay.add_toast( 82 | Adw.Toast(title=_("Preset downloaded"))) 83 | self.win.reload_pref_group() 84 | 85 | logging.debug("Apply and download completed") 86 | 87 | @Gtk.Template.Callback() 88 | def on_download_button_clicked(self, *_args): 89 | try: 90 | PresetDownloader().download_preset(to_slug_case(self.name), self.prefix, self.url) 91 | except (GLib.GError, json.JSONDecodeError, OSError): 92 | logging.error("An error occurred while trying to download a preset.") 93 | self.toast_overlay.add_toast( 94 | Adw.Toast(title=_("Preset could not be downloaded")) 95 | ) 96 | else: 97 | self.toast_overlay.add_toast( 98 | Adw.Toast(title=_("Preset downloaded"))) 99 | self.win.reload_pref_group() 100 | logging.debug("Download completed") 101 | -------------------------------------------------------------------------------- /gradience/frontend/widgets/meson.build: -------------------------------------------------------------------------------- 1 | widgetsdir = 'gradience/frontend/widgets' 2 | 3 | gradience_sources = [ 4 | '__init__.py', 5 | 'builtin_preset_row.py', 6 | 'custom_css_group.py', 7 | 'error_list_row.py', 8 | 'explore_preset_row.py', 9 | 'monet_theming_group.py', 10 | 'option_row.py', 11 | 'palette_shades.py', 12 | 'plugin_row.py', 13 | 'preset_row.py', 14 | 'repo_row.py', 15 | 'reset_preset_group.py', 16 | 'shell_theming_group.py', 17 | 'theming_empty_group.py', 18 | ] 19 | PY_INSTALLDIR.install_sources(gradience_sources, subdir: widgetsdir) 20 | -------------------------------------------------------------------------------- /gradience/frontend/widgets/palette_shades.py: -------------------------------------------------------------------------------- 1 | # palette_shades.py 2 | # 3 | # Change the look of Adwaita, with ease 4 | # Copyright (C) 2022 Gradience Team 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program. If not, see . 18 | 19 | from gi.repository import Gtk, Gdk, Adw 20 | 21 | from gradience.backend.constants import rootdir 22 | 23 | 24 | @Gtk.Template(resource_path=f"{rootdir}/ui/palette_shades.ui") 25 | class GradiencePaletteShades(Adw.ActionRow): 26 | __gtype_name__ = "GradiencePaletteShades" 27 | 28 | def __init__(self, prefix, color_title, n_shades, **kwargs): 29 | super().__init__(**kwargs) 30 | 31 | self.prefix = prefix 32 | self.set_name(prefix + "shades") 33 | self.set_title(color_title) 34 | self.set_subtitle("@" + prefix + "[1, " + str(n_shades) + "]") 35 | 36 | self.color_pickers = {} 37 | for i in range(1, n_shades + 1): 38 | picker = Gtk.ColorButton() 39 | picker.set_name(prefix + str(i)) 40 | picker.set_rgba(Gdk.RGBA(red=0, green=0, blue=0, alpha=0)) 41 | picker.set_valign(Gtk.Align.CENTER) 42 | picker.connect("color-set", self.on_color_changed) 43 | self.color_pickers[str(i)] = picker 44 | self.add_suffix(picker) 45 | 46 | def on_color_changed(self, *_args): 47 | shades = {} 48 | for picker_key, picker in self.color_pickers.items(): 49 | shades[picker_key] = picker.get_rgba().to_string() 50 | self.update_shades(shades, update_from="color_value") 51 | 52 | def update_shades(self, shades, **kwargs): 53 | for i in range(1, len(shades) + 1): 54 | new_rgba = Gdk.RGBA() 55 | if new_rgba.parse(shades[str(i)]): 56 | self.color_pickers[str(i)].set_rgba(new_rgba) 57 | self.color_pickers[str(i)].set_tooltip_text(shades[str(i)]) 58 | if ( 59 | Gtk.Application.get_default().is_ready 60 | and kwargs.get("update_from") == "color_value" 61 | ): 62 | Gtk.Application.get_default().palette[self.prefix][str(i)] = shades[ 63 | str(i) 64 | ] 65 | 66 | if ( 67 | Gtk.Application.get_default().is_ready 68 | and kwargs.get("update_from") == "color_value" 69 | ): 70 | Gtk.Application.get_default().mark_as_dirty() 71 | Gtk.Application.get_default().reload_variables() 72 | -------------------------------------------------------------------------------- /gradience/frontend/widgets/plugin_row.py: -------------------------------------------------------------------------------- 1 | # plugin_row.py 2 | # 3 | # Change the look of Adwaita, with ease 4 | # Copyright (C) 2022-2023, Gradience Team 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program. If not, see . 18 | 19 | import os 20 | 21 | from gi.repository import Gtk, Adw 22 | 23 | from gradience.frontend.views.no_plugin_window import GradienceNoPluginPrefWindow 24 | from gradience.backend.globals import user_plugin_dir 25 | from gradience.backend.constants import rootdir 26 | 27 | from gradience.backend.logger import Logger 28 | 29 | logging = Logger() 30 | 31 | 32 | @Gtk.Template(resource_path=f"{rootdir}/ui/plugin_row.ui") 33 | class GradiencePluginRow(Adw.ActionRow): 34 | __gtype_name__ = "GradiencePluginRow" 35 | 36 | switch = Gtk.Template.Child("switch") 37 | settings_button = Gtk.Template.Child("settings-button") 38 | remove_button = Gtk.Template.Child("remove-button") 39 | 40 | def __init__(self, plugin_object, preset, plugins_list, **kwargs): 41 | super().__init__(**kwargs) 42 | 43 | self.plugins_list = plugins_list 44 | 45 | self.plugin_object = plugin_object 46 | if not os.path.exists( 47 | os.path.join( 48 | user_plugin_dir, 49 | f"{self.plugin_object.plugin_id}.yapsy-plugin" 50 | ) 51 | ): 52 | self.remove_button.set_visible(False) 53 | 54 | self.set_name(plugin_object.plugin_id) 55 | self.set_title(plugin_object.title) 56 | self.set_subtitle("@" + plugin_object.plugin_id) 57 | 58 | self.enabled_plugins = self.plugins_list.enabled_plugins 59 | if self.plugin_object.plugin_id in self.enabled_plugins: 60 | self.switch.set_active(True) 61 | 62 | self.give_preset_settings(preset) 63 | 64 | @Gtk.Template.Callback() 65 | def on_settings_plugin_clicked(self, *_args): 66 | has_setting = self.plugin_object.open_settings() 67 | if not has_setting: 68 | win = GradienceNoPluginPrefWindow() 69 | win.set_transient_for(self.plugins_list.win) 70 | win.present() 71 | 72 | @Gtk.Template.Callback() 73 | def on_remove_plugin_clicked(self, *_args): 74 | plugin_yapsy_file = ( 75 | os.path.join( 76 | user_plugin_dir, 77 | f"{self.plugin_object.plugin_id}.yapsy-plugin" 78 | ) 79 | ) 80 | logging.debug(f"remove {plugin_yapsy_file}") 81 | try: 82 | os.remove(plugin_yapsy_file) 83 | except FileNotFoundError: 84 | error_dialog = Adw.MessageDialog( 85 | heading=_("Unable to remove"), 86 | body=_("This is a system plugin, and cannot be removed."), 87 | ) 88 | error_dialog.add_response("close", _("Close")) 89 | error_dialog.present() 90 | logging.debug(f"remove {plugin_yapsy_file}") 91 | Gtk.Application.get_default().reload_plugins() 92 | 93 | @Gtk.Template.Callback() 94 | def on_switch_toggled(self, *_args): 95 | if self.switch.get_active(): 96 | self.plugins_list.enable_plugin(self.plugin_object.plugin_id) 97 | else: 98 | self.plugins_list.disable_plugin(self.plugin_object.plugin_id) 99 | 100 | def give_preset_settings(self, preset_settings): 101 | self.preset_settings = preset_settings 102 | self.plugin_object.give_preset_settings(preset_settings) 103 | -------------------------------------------------------------------------------- /gradience/frontend/widgets/repo_row.py: -------------------------------------------------------------------------------- 1 | # repo_row.py 2 | # 3 | # Change the look of Adwaita, with ease 4 | # Copyright (C) 2022 Gradience Team 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program. If not, see . 18 | 19 | import os 20 | 21 | from gi.repository import Gtk, Adw 22 | 23 | from gradience.backend.constants import rootdir 24 | from gradience.backend.utils.common import to_slug_case 25 | 26 | 27 | @Gtk.Template(resource_path=f"{rootdir}/ui/repo_row.ui") 28 | class GradienceRepoRow(Adw.ActionRow): 29 | __gtype_name__ = "GradienceRepoRow" 30 | 31 | remove_button = Gtk.Template.Child("remove_button") 32 | 33 | def __init__(self, repo, repo_name, win, deletable=True, **kwargs): 34 | super().__init__(**kwargs) 35 | 36 | self.name = repo_name 37 | 38 | self.set_name(repo_name) 39 | self.set_title(repo_name) 40 | self.set_subtitle(repo) 41 | 42 | self.app = Gtk.Application.get_default() 43 | self.win = win 44 | self.toast_overlay = self.win.toast_overlay 45 | 46 | if not deletable: 47 | self.remove_button.set_visible(False) 48 | 49 | self.path = os.path.join( 50 | os.environ.get("XDG_CONFIG_HOME", os.environ["HOME"] + "/.config"), 51 | "presets", 52 | to_slug_case(repo_name), 53 | ) 54 | 55 | if not os.path.exists(self.path): 56 | os.makedirs(self.path) 57 | 58 | @Gtk.Template.Callback() 59 | def on_remove_button_clicked(self, *_args): 60 | self.toast_overlay.add_toast(Adw.Toast(title=_("Repository removed"))) 61 | 62 | self.win.remove_repo(self.name) 63 | 64 | self.win.reload_repos_group() 65 | -------------------------------------------------------------------------------- /gradience/frontend/widgets/reset_preset_group.py: -------------------------------------------------------------------------------- 1 | # reset_preset_group.py 2 | # 3 | # Change the look of Adwaita, with ease 4 | # Copyright (C) 2023, Gradience Team 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program. If not, see . 18 | 19 | from gi.repository import GLib, Gtk, Adw 20 | 21 | from gradience.backend.constants import rootdir 22 | from gradience.backend.logger import Logger 23 | from gradience.backend.theming.preset import PresetUtils 24 | 25 | logging = Logger() 26 | 27 | 28 | @Gtk.Template(resource_path=f"{rootdir}/ui/reset_preset_group.ui") 29 | class GradienceResetPresetGroup(Adw.PreferencesGroup): 30 | __gtype_name__ = "GradienceResetPresetGroup" 31 | 32 | def __init__(self, parent, **kwargs): 33 | super().__init__(**kwargs) 34 | 35 | self.parent = parent 36 | 37 | self.app = self.parent.get_application() 38 | self.win = self.parent 39 | 40 | self.setup_signals() 41 | self.setup() 42 | 43 | def setup_signals(self): 44 | pass 45 | 46 | def setup(self): 47 | pass 48 | 49 | @Gtk.Template.Callback() 50 | def on_libadw_restore_button_clicked(self, *_args): 51 | try: 52 | PresetUtils().restore_preset("gtk4") 53 | except GLib.GError: 54 | self.parent.add_toast( 55 | Adw.Toast(title=_("Unable to restore GTK 4 backup")) 56 | ) 57 | else: 58 | toast = Adw.Toast( 59 | title=_("GTK 4 preset has been restored. Log out to apply changes."), 60 | ) 61 | self.parent.add_toast(toast) 62 | 63 | @Gtk.Template.Callback() 64 | def on_libadw_reset_button_clicked(self, *_args): 65 | try: 66 | PresetUtils().reset_preset("gtk4") 67 | except GLib.GError: 68 | self.parent.add_toast( 69 | Adw.Toast(title=_("Unable to delete current preset")) 70 | ) 71 | else: 72 | toast = Adw.Toast( 73 | title=_("GTK 4 theme has been reset. Log out to apply changes."), 74 | ) 75 | self.parent.add_toast(toast) 76 | 77 | 78 | @Gtk.Template.Callback() 79 | def on_gtk3_restore_button_clicked(self, *_args): 80 | try: 81 | PresetUtils().restore_preset("gtk3") 82 | except GLib.GError: 83 | self.parent.add_toast( 84 | Adw.Toast(title=_("Unable to restore GTK 3 backup")) 85 | ) 86 | else: 87 | toast = Adw.Toast( 88 | title=_("GTK 3 preset has been restored. Log out to apply changes."), 89 | ) 90 | self.parent.add_toast(toast) 91 | 92 | @Gtk.Template.Callback() 93 | def on_gtk3_reset_button_clicked(self, *_args): 94 | try: 95 | PresetUtils().reset_preset("gtk3") 96 | except GLib.GError: 97 | self.parent.add_toast( 98 | Adw.Toast(title=_("Unable to delete current preset")) 99 | ) 100 | else: 101 | toast = Adw.Toast( 102 | title=_("GTK 3 theme has been reset. Log out to apply changes."), 103 | ) 104 | self.parent.add_toast(toast) 105 | -------------------------------------------------------------------------------- /gradience/frontend/widgets/theming_empty_group.py: -------------------------------------------------------------------------------- 1 | # theming_empty_group.py 2 | # 3 | # Change the look of Adwaita, with ease 4 | # Copyright (C) 2023, Gradience Team 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program. If not, see . 18 | 19 | from enum import Enum 20 | 21 | from gi.repository import Adw, Gio, GLib, Gtk 22 | 23 | from gradience.backend.constants import rootdir 24 | from gradience.backend.exceptions import UnsupportedShellVersion 25 | from gradience.backend.logger import Logger 26 | from gradience.backend.theming.shell import ShellTheme 27 | 28 | from gradience.frontend.views.shell_prefs_window import GradienceShellPrefsWindow 29 | 30 | logging = Logger() 31 | 32 | 33 | @Gtk.Template(resource_path=f"{rootdir}/ui/theming_empty_group.ui") 34 | class GradienceEmptyThemingGroup(Adw.PreferencesGroup): 35 | __gtype_name__ = "GradienceEmptyThemingGroup" 36 | 37 | def __init__(self, parent, **kwargs): 38 | super().__init__(**kwargs) 39 | 40 | self.parent = parent 41 | self.settings = parent.settings 42 | self.app = self.parent.get_application() 43 | 44 | self.setup_signals() 45 | self.setup() 46 | 47 | def setup_signals(self): 48 | pass 49 | 50 | def setup(self): 51 | pass 52 | -------------------------------------------------------------------------------- /gradience/meson.build: -------------------------------------------------------------------------------- 1 | moduledir = 'gradience' 2 | 3 | subdir('backend') 4 | subdir('frontend') 5 | 6 | gradience_sources = [ 7 | '__init__.py' 8 | ] 9 | PY_INSTALLDIR.install_sources(gradience_sources, subdir: moduledir) 10 | -------------------------------------------------------------------------------- /local.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/bash 2 | 3 | # local.sh 4 | # 5 | # Change the look of Adwaita, with ease 6 | # Copyright (C) 2022 Gradience Team 7 | # 8 | # This program is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU General Public License as published by 10 | # the Free Software Foundation, either version 3 of the License, or 11 | # (at your option) any later version. 12 | # 13 | # This program is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU General Public License 19 | # along with this program. If not, see . 20 | 21 | read -p "Do you want to install Python requirements? [N/y] " answer 22 | 23 | if [[ "$answer" == "y" ]]; then 24 | pip3 install -r requirements.txt 25 | elif [[ "$answer" == "n" || "$answer" == "" ]]; then 26 | echo "Skipping requirements installation" 27 | fi 28 | 29 | echo "Cleaning builddir directory" 30 | rm -r builddir 31 | 32 | echo "Rebuilding" 33 | meson setup builddir 34 | meson configure builddir -Dprefix="$(pwd)/builddir" -Dbuildtype=debug 35 | ninja -C builddir install 36 | 37 | echo "Running" 38 | ninja -C builddir run 39 | -------------------------------------------------------------------------------- /local_cli.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/bash 2 | 3 | # local_cli.sh 4 | # 5 | # Change the look of Adwaita, with ease 6 | # Copyright (C) 2022 Gradience Team 7 | # 8 | # This program is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU General Public License as published by 10 | # the Free Software Foundation, either version 3 of the License, or 11 | # (at your option) any later version. 12 | # 13 | # This program is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU General Public License 19 | # along with this program. If not, see . 20 | 21 | python builddir/gradience/frontend/local-gradience-cli "$@" 22 | -------------------------------------------------------------------------------- /meson.build: -------------------------------------------------------------------------------- 1 | project('gradience', 2 | version: '0.8.0-beta2', 3 | meson_version: '>= 0.59.0', 4 | default_options: [ 'warning_level=2', 5 | 'werror=false', 6 | ], 7 | ) 8 | 9 | # Import modules 10 | gnome = import('gnome') 11 | i18n = import('i18n') 12 | python = import('python') 13 | 14 | # Project information 15 | PROJECT_URL = 'https://github.com/GradienceTeam/Gradience' 16 | BUGTRACKER_URL = 'https://github.com/GradienceTeam/Gradience/issues' 17 | HELP_URL = 'https://github.com/GradienceTeam/Gradience/discussions' 18 | TRANSLATE_URL = 'https://hosted.weblate.org/projects/GradienceTeam/gradience' 19 | 20 | # Constants 21 | PROJECT_RDNN_NAME = 'com.github.GradienceTeam.Gradience' 22 | 23 | git_bin = find_program('git', required: false) 24 | 25 | # Set APPLICATION_ID and VERSION_SUFFIX 26 | if get_option('buildtype') == 'debug' 27 | if git_bin.found() 28 | VCS_TAG = run_command('git', 'rev-parse', '--short', 'HEAD', check: true).stdout().strip() 29 | else 30 | VCS_TAG = '' 31 | endif 32 | if VCS_TAG == '' 33 | VERSION_SUFFIX = '-devel' 34 | else 35 | VERSION_SUFFIX = '-@0@'.format(VCS_TAG) 36 | endif 37 | APPLICATION_ID = '@0@.Devel'.format(PROJECT_RDNN_NAME) 38 | else 39 | VERSION_SUFFIX = '' 40 | APPLICATION_ID = PROJECT_RDNN_NAME 41 | endif 42 | 43 | dependency('glib-2.0') 44 | dependency('gtk4', version: '>= 4.5.0') 45 | dependency('libadwaita-1', version: '>= 1.2.alpha') 46 | dependency('pygobject-3.0', version: '>= 3.42.0') 47 | dependency('libsoup-3.0', version: '>= 3.2.0') 48 | 49 | # Python installation directory 50 | PY_INSTALLDIR = python.find_installation('python3', required: true, modules: ['lxml']) 51 | 52 | # Check if python3 is installed 53 | if not PY_INSTALLDIR.found() 54 | error('No valid python3 binary found') 55 | endif 56 | 57 | PKGDATA_DIR = join_paths(get_option('prefix'), get_option('datadir'), meson.project_name()) 58 | MODULE_DIR = join_paths(PKGDATA_DIR, 'gradience') 59 | PLUGINS_DIR = join_paths(PKGDATA_DIR, 'gradience', 'plugins') 60 | 61 | # Install configuration data 62 | conf = configuration_data() 63 | conf.set('APP_ID', APPLICATION_ID) 64 | conf.set('PKGDATA_DIR', PKGDATA_DIR) 65 | conf.set('DATA_DIR', join_paths(get_option('prefix'), get_option('datadir'))) 66 | conf.set('LOCALE_DIR', join_paths(get_option('prefix'), get_option('localedir'))) 67 | conf.set('PYTHON', PY_INSTALLDIR.full_path()) 68 | conf.set('VERSION', meson.project_version() + VERSION_SUFFIX) 69 | conf.set('BUILD_TYPE', get_option('buildtype')) 70 | conf.set('SCHEMAS_DIR', PKGDATA_DIR) 71 | conf.set('SOURCE_DIR', meson.current_source_dir()) 72 | conf.set('BUILD_DIR', meson.current_build_dir()) 73 | 74 | conf.set('local_build', 'False') 75 | 76 | # Local install configuration data 77 | local_conf = configuration_data() 78 | local_conf.set('APP_ID', APPLICATION_ID) 79 | local_conf.set('PKGDATA_DIR', join_paths(meson.current_build_dir(), 'data')) 80 | local_conf.set('LOCALE_DIR', join_paths(get_option('prefix'), get_option('datadir'), 'locale')) 81 | local_conf.set('PYTHON', meson.current_source_dir()) 82 | local_conf.set('VERSION', meson.project_version() + VERSION_SUFFIX) 83 | local_conf.set('BUILD_TYPE', get_option('buildtype')) 84 | local_conf.set('SCHEMAS_DIR', join_paths(meson.current_build_dir(), get_option('datadir'))) 85 | local_conf.set('SOURCE_DIR', meson.current_source_dir()) 86 | local_conf.set('BUILD_DIR', meson.current_build_dir()) 87 | 88 | local_conf.set('local_build', 'True') 89 | 90 | # Subdirs 91 | subdir('gradience') 92 | subdir('data') 93 | subdir('po') 94 | 95 | gnome.post_install( 96 | glib_compile_schemas: true, 97 | gtk_update_icon_cache: true, 98 | update_desktop_database: true, 99 | ) 100 | -------------------------------------------------------------------------------- /po/LINGUAS: -------------------------------------------------------------------------------- 1 | ar 2 | cs 3 | de 4 | es 5 | eu 6 | fi 7 | fr 8 | hr 9 | id 10 | it 11 | ko 12 | nl 13 | oc 14 | pl 15 | pt_BR 16 | ru 17 | sv 18 | ta 19 | tr 20 | zh_Hans 21 | ro 22 | az 23 | sr 24 | uk 25 | pt 26 | hi 27 | he 28 | -------------------------------------------------------------------------------- /po/POTFILES: -------------------------------------------------------------------------------- 1 | data/com.github.GradienceTeam.Gradience.appdata.xml.in.in 2 | data/com.github.GradienceTeam.Gradience.desktop.in.in 3 | data/com.github.GradienceTeam.Gradience.gschema.xml.in 4 | data/ui/app_type_dialog.blp 5 | data/ui/builtin_preset_row.blp 6 | data/ui/custom_css_group.blp 7 | data/ui/explore_preset_row.blp 8 | data/ui/help_overlay.blp 9 | data/ui/log_out_dialog.blp 10 | data/ui/monet_theming_group.blp 11 | data/ui/no_plugin_window.blp 12 | data/ui/option_row.blp 13 | data/ui/plugin_row.blp 14 | data/ui/preferences_window.blp 15 | data/ui/preset_row.blp 16 | data/ui/presets_manager_window.blp 17 | data/ui/repo_row.blp 18 | data/ui/reset_preset_group.blp 19 | data/ui/save_dialog.blp 20 | data/ui/share_window.blp 21 | data/ui/shell_prefs_window.blp 22 | data/ui/shell_theming_group.blp 23 | data/ui/theming_empty_group.blp 24 | data/ui/welcome_window.blp 25 | data/ui/window.blp 26 | gradience/backend/flatpak_overrides.py 27 | gradience/frontend/dialogs/app_type_dialog.py 28 | gradience/frontend/dialogs/save_dialog.py 29 | gradience/frontend/dialogs/unsupported_shell_dialog.py 30 | gradience/frontend/main.py 31 | gradience/frontend/schemas/preset_schema.py 32 | gradience/frontend/schemas/shell_schema.py 33 | gradience/frontend/views/about_window.py 34 | gradience/frontend/views/main_window.py 35 | gradience/frontend/views/plugins_list.py 36 | gradience/frontend/views/presets_manager_window.py 37 | gradience/frontend/views/welcome_window.py 38 | gradience/frontend/widgets/explore_preset_row.py 39 | gradience/frontend/widgets/monet_theming_group.py 40 | gradience/frontend/widgets/option_row.py 41 | gradience/frontend/widgets/plugin_row.py 42 | gradience/frontend/widgets/preset_row.py 43 | gradience/frontend/widgets/repo_row.py 44 | gradience/frontend/widgets/reset_preset_group.py 45 | gradience/frontend/widgets/shell_theming_group.py 46 | -------------------------------------------------------------------------------- /po/meson.build: -------------------------------------------------------------------------------- 1 | i18n.gettext(meson.project_name(), preset: 'glib') 2 | -------------------------------------------------------------------------------- /po/update_linguas.py: -------------------------------------------------------------------------------- 1 | # Change the look of Adwaita, with ease 2 | # Copyright (C) 2022 Gradience Team 3 | # 4 | # This program is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | 17 | 18 | import os 19 | 20 | 21 | def list_po(): 22 | files = [] 23 | for _, _, filenames in os.walk("po"): 24 | for file in filenames: 25 | if file.endswith(".po"): 26 | files.append(file.strip(".po")) 27 | return files 28 | 29 | 30 | with open("LINGUAS", "w") as file: 31 | po = "\n".join(list_po()) 32 | file.write(po) 33 | -------------------------------------------------------------------------------- /po/update_potfile.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | po_dir=$(dirname "$(realpath "$0")") 3 | xgettext -f "$po_dir"/POTFILES -o "$po_dir"/Gradience.pot --add-comments=Translators --keyword=_ --keyword=C_1c,2 --from-code=UTF-8 4 | sed -i "s/SOME DESCRIPTIVE TITLE./Gradience POT file/" "$po_dir"/Gradience.pot 5 | sed -i "s/YEAR THE PACKAGE'S COPYRIGHT HOLDER/$(date +%Y) Gradience Team/" "$po_dir"/Gradience.pot 6 | sed -i "s@same license as the PACKAGE package.@GNU GPLv3 license.@" "$po_dir"/Gradience.pot 7 | sed -i "s/FIRST AUTHOR , YEAR./Gradience Team, $(date +%Y)./" "$po_dir"/Gradience.pot 8 | 9 | regex="$po_dir/([a-zA-Z_]*).po" 10 | find "$po_dir" -type f -name "*.po" | sed -rn "s:$regex:\1:p" > "$po_dir/LINGUAS" 11 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | # requirements.txt 2 | # 3 | # Change the look of Adwaita, with ease 4 | # Copyright (C) 2022 Gradience Team 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program. If not, see . 18 | 19 | # After changing this file, download the flatpak pip generator script: 20 | # curl -O https://raw.githubusercontent.com/flatpak/flatpak-builder-tools/master/pip/flatpak-pip-generator 21 | # chmod +x flatpak-pip-generator 22 | # Then run: 23 | # ./flatpak-pip-generator --requirements-file=requirements.txt --output pypi-dependencies 24 | # And move output file to build-aux directory: 25 | # mv pypi-dependencies.json build-aux/flatpak/ 26 | # 27 | # or more simply, just push and the bot will do this for you. 28 | 29 | anyascii 30 | material-color-utilities-python 31 | svglib 32 | yapsy 33 | Jinja2 34 | libsass -------------------------------------------------------------------------------- /typos.toml: -------------------------------------------------------------------------------- 1 | [type.po] 2 | extend-glob = ["*.po"] 3 | check-file = false 4 | 5 | [type.svg] 6 | extend-glob = ["*.svg"] 7 | check-file = false 8 | --------------------------------------------------------------------------------