perf: improving performance, layout (#215)
Co-authored-by: nullishamy <git@amyerskine.me>
49
.github/workflows/build.yml
vendored
@@ -3,33 +3,64 @@ name: "Generate test artifacts"
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, reopened, synchronize]
|
||||
|
||||
# env:
|
||||
# TAG: latest
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
# container:
|
||||
# image: ghcr.io/${{ github.repository_owner }}/${{ github.repository }}:${{ env.TAG }}
|
||||
#
|
||||
# # is this really necessary?
|
||||
# credentials:
|
||||
# username: ${{ github.actor }}
|
||||
# password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
steps:
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.11"
|
||||
cache: "pip"
|
||||
|
||||
- name: Install dependencies
|
||||
run: pip install -r requirements.txt
|
||||
- name: Install colloid specific dependencies
|
||||
run: sudo apt update && sudo apt install -y sassc inkscape optipng
|
||||
run: |
|
||||
sudo apt update && sudo apt install -y sassc inkscape optipng
|
||||
pip install -r requirements.txt
|
||||
|
||||
- name: Generate themes
|
||||
run: |
|
||||
python patches/xfwm4/generate_assets.py
|
||||
set -eu pipefile
|
||||
|
||||
python sources/patches/xfwm4/generate_assets.py
|
||||
|
||||
python ./build.py mocha --all-accents --zip -d $PWD/releases > mocha.log 2>&1 &
|
||||
python ./build.py macchiato --all-accents --zip -d $PWD/releases > macchiato.log 2>&1 &
|
||||
python ./build.py frappe --all-accents --zip -d $PWD/releases > frappe.log 2>&1 &
|
||||
python ./build.py latte --all-accents --zip -d $PWD/releases > latte.log 2>&1 &
|
||||
|
||||
declare -i err=0 werr=0
|
||||
while wait -fn || werr=$?; ((werr != 127)); do
|
||||
err=$werr
|
||||
if [[ $err -ne 0 ]]; then
|
||||
echo "Build failure, abort"
|
||||
cat *.log
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
cat *.log
|
||||
|
||||
python ./build.py mocha --all-accents --zip -d $PWD/releases &&
|
||||
python ./build.py macchiato --all-accents --zip -d $PWD/releases &&
|
||||
python ./build.py frappe --all-accents --zip -d $PWD/releases &&
|
||||
python ./build.py latte --all-accents --zip -d $PWD/releases
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: '${{ github.sha }}-artifacts'
|
||||
path: ./releases/*.zip
|
||||
|
||||
|
27
.github/workflows/docker.yml
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
name: "Publish containers for build"
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
pull_request:
|
||||
# types: [opened, reopened, synchronize]
|
||||
types: [synchronize]
|
||||
|
||||
permissions: write-all
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Generate and push image to ghcr
|
||||
run: |
|
||||
# build docker image for the ci
|
||||
sh docker/build.sh -v no
|
||||
|
||||
# push the image to the registry
|
||||
sh docker/push.sh -u "${{ github.actor }}" -p "${{ secrets.GITHUB_TOKEN }}"
|
28
.github/workflows/release.yml
vendored
@@ -28,22 +28,40 @@ jobs:
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.11"
|
||||
cache: "pip"
|
||||
|
||||
- name: Install dependencies
|
||||
run: pip install -r requirements.txt
|
||||
|
||||
- name: Install colloid specific dependencies
|
||||
run: sudo apt update && sudo apt install -y sassc inkscape optipng
|
||||
|
||||
- name: Generate themes
|
||||
run: |
|
||||
python patches/xfwm4/generate_assets.py
|
||||
set -eu pipefile
|
||||
|
||||
python sources/patches/xfwm4/generate_assets.py
|
||||
|
||||
python ./build.py mocha --all-accents --zip -d $PWD/releases > mocha.log 2>&1 &
|
||||
python ./build.py macchiato --all-accents --zip -d $PWD/releases > macchiato.log 2>&1 &
|
||||
python ./build.py frappe --all-accents --zip -d $PWD/releases > frappe.log 2>&1 &
|
||||
python ./build.py latte --all-accents --zip -d $PWD/releases > latte.log 2>&1 &
|
||||
declare -i err=0 werr=0
|
||||
while wait -fn || werr=$?; ((werr != 127)); do
|
||||
err=$werr
|
||||
if [[ $err -ne 0 ]]; then
|
||||
echo "Build failure, abort"
|
||||
cat *.log
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
cat *.log
|
||||
|
||||
python ./build.py mocha --all-accents --zip -d $PWD/releases &&
|
||||
python ./build.py macchiato --all-accents --zip -d $PWD/releases &&
|
||||
python ./build.py frappe --all-accents --zip -d $PWD/releases &&
|
||||
python ./build.py latte --all-accents --zip -d $PWD/releases
|
||||
- name: Add zips to release
|
||||
run: gh release upload ${{ needs.release-please.outputs.tag_name }} releases/*.zip
|
||||
env:
|
||||
|
3
.gitignore
vendored
@@ -8,6 +8,9 @@ lib*/
|
||||
*.cfg
|
||||
.direnv
|
||||
build/
|
||||
*.log
|
||||
.ruff-cache
|
||||
.tmp
|
||||
|
||||
# Releases folder
|
||||
releases
|
||||
|
2
.gitmodules
vendored
@@ -1,3 +1,3 @@
|
||||
[submodule "colloid"]
|
||||
path = colloid
|
||||
path = sources/colloid
|
||||
url = https://github.com/vinceliuice/Colloid-gtk-theme.git
|
||||
|
646
build.py
@@ -1,636 +1,22 @@
|
||||
#!/usr/bin/env python3
|
||||
import os, re, shutil, subprocess, argparse, glob, logging, zipfile, sys
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import os
|
||||
|
||||
from dataclasses import dataclass
|
||||
from typing import Any, Literal, List
|
||||
from sources.build import execute_build
|
||||
from sources.build.args import parse_args
|
||||
from sources.build.logger import logger
|
||||
|
||||
from catppuccin import PALETTE
|
||||
from catppuccin.models import Flavor, Color
|
||||
|
||||
THIS_DIR = os.path.dirname(os.path.realpath(__file__))
|
||||
SRC_DIR = f"{THIS_DIR}/colloid/src"
|
||||
SASSC_OPT = ["-M", "-t", "expanded"]
|
||||
|
||||
logger = logging.getLogger("catppuccin-gtk")
|
||||
logger.setLevel(logging.DEBUG)
|
||||
ch = logging.StreamHandler()
|
||||
formatter = logging.Formatter("[%(name)s] [%(levelname)s] - %(message)s")
|
||||
ch.setFormatter(formatter)
|
||||
logger.addHandler(ch)
|
||||
|
||||
|
||||
@dataclass
|
||||
class Tweaks:
|
||||
tweaks: List[str]
|
||||
|
||||
def has(self, tweak: str) -> bool:
|
||||
return tweak in self.tweaks
|
||||
|
||||
def id(self) -> str:
|
||||
return ",".join(self.tweaks)
|
||||
|
||||
|
||||
@dataclass
|
||||
class Suffix:
|
||||
true_value: str
|
||||
test: Any # callback function
|
||||
false_value: str = ""
|
||||
|
||||
|
||||
IS_DARK = Suffix(true_value="-Dark", test=lambda ctx: ctx.flavor.dark)
|
||||
IS_LIGHT = Suffix(true_value="-Light", test=lambda ctx: not ctx.flavor.dark)
|
||||
IS_WINDOW_NORMAL = Suffix(true_value="-Normal", test=lambda ctx: ctx.tweaks.has('normal'))
|
||||
DARK_LIGHT = Suffix(
|
||||
true_value="-Dark", false_value="-Light", test=lambda ctx: ctx.flavor.dark
|
||||
)
|
||||
|
||||
@dataclass
|
||||
class BuildContext:
|
||||
build_root: str
|
||||
output_format: Literal["zip"] | Literal["dir"]
|
||||
theme_name: str
|
||||
flavor: Flavor
|
||||
accent: Color
|
||||
size: Literal["standard"] | Literal["compact"]
|
||||
tweaks: Tweaks
|
||||
|
||||
def output_dir(self) -> str:
|
||||
suffix = "light"
|
||||
if self.flavor.dark:
|
||||
suffix = "dark"
|
||||
return f"{self.build_root}/{self.build_id()}-{suffix}"
|
||||
|
||||
def build_id(self) -> str:
|
||||
return f"{self.theme_name}-{self.flavor.identifier}-{self.accent.identifier}-{self.size}+{self.tweaks.id() or 'default'}"
|
||||
|
||||
def apply_suffix(self, suffix: Suffix) -> str:
|
||||
if suffix.test(self):
|
||||
return suffix.true_value
|
||||
else:
|
||||
return suffix.false_value
|
||||
|
||||
|
||||
def build(ctx: BuildContext):
|
||||
output_dir = ctx.output_dir()
|
||||
logger.info(f"Building into '{output_dir}'...")
|
||||
|
||||
apply_tweaks(ctx)
|
||||
|
||||
os.makedirs(output_dir, exist_ok=True)
|
||||
with open(f"{output_dir}/index.theme", "w") as file:
|
||||
file.write("[Desktop Entry]\n")
|
||||
file.write("Type=X-GNOME-Metatheme\n")
|
||||
file.write(f"Name={ctx.build_id()}\n")
|
||||
file.write("Comment=An Flat Gtk+ theme based on Elegant Design\n")
|
||||
file.write("Encoding=UTF-8\n")
|
||||
file.write("\n")
|
||||
file.write("[X-GNOME-Metatheme]\n")
|
||||
file.write(f"GtkTheme={ctx.build_id()}\n")
|
||||
file.write(f"MetacityTheme={ctx.build_id()}\n")
|
||||
file.write(f"IconTheme=Tela-circle{ctx.apply_suffix(IS_DARK)}\n")
|
||||
file.write(f"CursorTheme={ctx.flavor.name}-cursors\n")
|
||||
file.write("ButtonLayout=close,minimize,maximize:menu\n")
|
||||
|
||||
os.makedirs(f"{output_dir}/gnome-shell", exist_ok=True)
|
||||
shutil.copyfile(
|
||||
f"{SRC_DIR}/main/gnome-shell/pad-osd.css",
|
||||
f"{output_dir}/gnome-shell/pad-osd.css",
|
||||
)
|
||||
subprocess.check_call(
|
||||
[
|
||||
"sassc",
|
||||
*SASSC_OPT,
|
||||
f"{SRC_DIR}/main/gnome-shell/gnome-shell{ctx.apply_suffix(DARK_LIGHT)}.scss",
|
||||
f"{output_dir}/gnome-shell/gnome-shell.css",
|
||||
]
|
||||
)
|
||||
|
||||
os.makedirs(f"{output_dir}/gtk-3.0", exist_ok=True)
|
||||
subprocess.check_call(
|
||||
[
|
||||
"sassc",
|
||||
*SASSC_OPT,
|
||||
f"{SRC_DIR}/main/gtk-3.0/gtk{ctx.apply_suffix(DARK_LIGHT)}.scss",
|
||||
f"{output_dir}/gtk-3.0/gtk.css",
|
||||
]
|
||||
)
|
||||
subprocess.check_call(
|
||||
[
|
||||
"sassc",
|
||||
*SASSC_OPT,
|
||||
# NOTE: This uses 'Dark' for the source, but 'dark' for the destination. This is intentional. Do !!NOT!! change it without consultation
|
||||
f"{SRC_DIR}/main/gtk-3.0/gtk-Dark.scss",
|
||||
f"{output_dir}/gtk-3.0/gtk-dark.css",
|
||||
]
|
||||
)
|
||||
|
||||
os.makedirs(f"{output_dir}/gtk-4.0", exist_ok=True)
|
||||
subprocess.check_call(
|
||||
[
|
||||
"sassc",
|
||||
*SASSC_OPT,
|
||||
f"{SRC_DIR}/main/gtk-4.0/gtk{ctx.apply_suffix(DARK_LIGHT)}.scss",
|
||||
f"{output_dir}/gtk-4.0/gtk.css",
|
||||
]
|
||||
)
|
||||
subprocess.check_call(
|
||||
[
|
||||
"sassc",
|
||||
*SASSC_OPT,
|
||||
# NOTE: This uses 'Dark' for the source, but 'dark' for the destination. This is intentional. Do !!NOT!! change it without consultation
|
||||
f"{SRC_DIR}/main/gtk-4.0/gtk-Dark.scss",
|
||||
f"{output_dir}/gtk-4.0/gtk-dark.css",
|
||||
]
|
||||
)
|
||||
|
||||
os.makedirs(f"{output_dir}/cinnamon", exist_ok=True)
|
||||
subprocess.check_call(
|
||||
[
|
||||
"sassc",
|
||||
*SASSC_OPT,
|
||||
f"{SRC_DIR}/main/cinnamon/cinnamon{ctx.apply_suffix(DARK_LIGHT)}.scss",
|
||||
f"{output_dir}/cinnamon/cinnamon.css",
|
||||
]
|
||||
)
|
||||
|
||||
os.makedirs(f"{output_dir}/metacity-1", exist_ok=True)
|
||||
shutil.copyfile(
|
||||
f"{SRC_DIR}/main/metacity-1/metacity-theme-3{ctx.apply_suffix(IS_WINDOW_NORMAL)}.xml",
|
||||
f"{output_dir}/metacity-1/metacity-theme-3.xml",
|
||||
)
|
||||
# FIXME: Symlinks aren't working as intended
|
||||
# FIXME: Do we need them?
|
||||
# os.symlink(
|
||||
# f"{output_dir}/metacity-1/metacity-theme-3.xml",
|
||||
# f"{output_dir}/metacity-1/metacity-theme-2.xml",
|
||||
# )
|
||||
# os.symlink(
|
||||
# f"{output_dir}/metacity-1/metacity-theme-3.xml",
|
||||
# f"{output_dir}/metacity-1/metacity-theme-1.xml",
|
||||
# )
|
||||
|
||||
os.makedirs(f"{output_dir}/xfwm4", exist_ok=True)
|
||||
shutil.copyfile(
|
||||
f"{SRC_DIR}/main/xfwm4/themerc{ctx.apply_suffix(IS_LIGHT)}",
|
||||
f"{output_dir}/xfwm4/themerc",
|
||||
)
|
||||
|
||||
os.makedirs(f"{output_dir}-hdpi/xfwm4", exist_ok=True)
|
||||
shutil.copyfile(
|
||||
f"{SRC_DIR}/main/xfwm4/themerc{ctx.apply_suffix(IS_LIGHT)}",
|
||||
f"{output_dir}-hdpi/xfwm4/themerc",
|
||||
)
|
||||
subst_text(f"{output_dir}-hdpi/xfwm4/themerc", "button_offset=6", "button_offset=9")
|
||||
|
||||
os.makedirs(f"{output_dir}-xhdpi/xfwm4", exist_ok=True)
|
||||
shutil.copyfile(
|
||||
f"{SRC_DIR}/main/xfwm4/themerc{ctx.apply_suffix(IS_LIGHT)}",
|
||||
f"{output_dir}-xhdpi/xfwm4/themerc",
|
||||
)
|
||||
subst_text(
|
||||
f"{output_dir}-xhdpi/xfwm4/themerc", "button_offset=6", "button_offset=12"
|
||||
)
|
||||
|
||||
if not ctx.flavor.dark:
|
||||
shutil.copytree(
|
||||
f"{SRC_DIR}/main/plank/theme-Light-Catppuccin/", f"{output_dir}/plank", dirs_exist_ok=True
|
||||
)
|
||||
else:
|
||||
shutil.copytree(
|
||||
f"{SRC_DIR}/main/plank/theme-Dark-Catppuccin/", f"{output_dir}/plank", dirs_exist_ok=True
|
||||
)
|
||||
|
||||
|
||||
def init_tweaks_temp():
|
||||
shutil.copyfile(f"{SRC_DIR}/sass/_tweaks.scss", f"{SRC_DIR}/sass/_tweaks-temp.scss")
|
||||
|
||||
|
||||
def subst_text(path, _from, to):
|
||||
with open(path, "r+") as f:
|
||||
content = f.read()
|
||||
f.seek(0)
|
||||
f.truncate()
|
||||
f.write(re.sub(_from, to, content))
|
||||
|
||||
|
||||
GS_VERSION = "46-0"
|
||||
|
||||
def gnome_shell_version():
|
||||
shutil.copyfile(
|
||||
f"{SRC_DIR}/sass/gnome-shell/_common.scss",
|
||||
f"{SRC_DIR}/sass/gnome-shell/_common-temp.scss",
|
||||
)
|
||||
subst_text(
|
||||
f"{SRC_DIR}/sass/gnome-shell/_common-temp.scss",
|
||||
"@import 'widgets-40-0';",
|
||||
f"@import 'widgets-{GS_VERSION}';",
|
||||
)
|
||||
|
||||
if GS_VERSION == "3-28":
|
||||
subst_text(
|
||||
f"{SRC_DIR}/sass/gnome-shell/_common-temp.scss",
|
||||
"@import 'extensions-40-0';",
|
||||
f"@import 'extensions-{GS_VERSION}';",
|
||||
)
|
||||
|
||||
def write_tweak(key, default, value):
|
||||
subst_text(
|
||||
f"{SRC_DIR}/sass/_tweaks-temp.scss", f"\\${key}: {default}", f"${key}: {value}"
|
||||
)
|
||||
|
||||
def apply_tweaks(ctx: BuildContext):
|
||||
write_tweak("theme", "'default'", f"'{ctx.accent.identifier}'")
|
||||
|
||||
if ctx.size == "compact":
|
||||
write_tweak("compact", "'false'", "'true'")
|
||||
|
||||
subst_text(
|
||||
f"{SRC_DIR}/sass/_tweaks-temp.scss",
|
||||
"@import 'color-palette-default';",
|
||||
f"@import 'color-palette-catppuccin-{ctx.flavor.identifier}';",
|
||||
)
|
||||
write_tweak("colorscheme", "'default'", "'catppuccin'")
|
||||
|
||||
if ctx.tweaks.has("black"):
|
||||
write_tweak("blackness", "'false'", "'true'")
|
||||
|
||||
if ctx.tweaks.has("rimless"):
|
||||
write_tweak("rimless", "'false'", "'true'")
|
||||
|
||||
if ctx.tweaks.has("normal"):
|
||||
write_tweak("window_button", "'mac'", "'normal'")
|
||||
|
||||
if ctx.tweaks.has("float"):
|
||||
write_tweak("float", "'false'", "'true'")
|
||||
|
||||
|
||||
def make_assets(ctx: BuildContext):
|
||||
output_dir = ctx.output_dir()
|
||||
|
||||
os.makedirs(f"{output_dir}/cinnamon/assets", exist_ok=True)
|
||||
for file in glob.glob(f"{SRC_DIR}/assets/cinnamon/theme/*.svg"):
|
||||
shutil.copy(file, f"{output_dir}/cinnamon/assets")
|
||||
shutil.copy(
|
||||
f"{SRC_DIR}/assets/cinnamon/thumbnail{ctx.apply_suffix(DARK_LIGHT)}.svg",
|
||||
f"{output_dir}/cinnamon/thumbnail.png",
|
||||
)
|
||||
|
||||
os.makedirs(f"{output_dir}/gnome-shell/assets", exist_ok=True)
|
||||
for file in glob.glob(f"{SRC_DIR}/assets/gnome-shell/theme/*.svg"):
|
||||
shutil.copy(file, f"{output_dir}/gnome-shell/assets")
|
||||
|
||||
shutil.copytree(
|
||||
f"{SRC_DIR}/assets/gtk/assets",
|
||||
f"{output_dir}/gtk-3.0/assets",
|
||||
dirs_exist_ok=True,
|
||||
)
|
||||
shutil.copytree(
|
||||
f"{SRC_DIR}/assets/gtk/assets",
|
||||
f"{output_dir}/gtk-4.0/assets",
|
||||
dirs_exist_ok=True,
|
||||
)
|
||||
shutil.copyfile(
|
||||
f"{SRC_DIR}/assets/gtk/thumbnail{ctx.apply_suffix(IS_DARK)}.svg",
|
||||
f"{output_dir}/gtk-3.0/thumbnail.png",
|
||||
)
|
||||
shutil.copyfile(
|
||||
f"{SRC_DIR}/assets/gtk/thumbnail{ctx.apply_suffix(IS_DARK)}.svg",
|
||||
f"{output_dir}/gtk-4.0/thumbnail.png",
|
||||
)
|
||||
|
||||
theme_color = ctx.accent.hex
|
||||
|
||||
palette = ctx.flavor.colors
|
||||
background = palette.base.hex
|
||||
background_alt = palette.mantle.hex
|
||||
titlebar = palette.overlay0.hex
|
||||
|
||||
for file in glob.glob(f"{output_dir}/cinnamon/assets/*.svg"):
|
||||
subst_text(file, "#5b9bf8", theme_color)
|
||||
subst_text(file, "#3c84f7", theme_color)
|
||||
|
||||
for file in glob.glob(f"{output_dir}/gnome-shell/assets/*.svg"):
|
||||
subst_text(file, "#5b9bf8", theme_color)
|
||||
subst_text(file, "#3c84f7", theme_color)
|
||||
|
||||
for file in glob.glob(f"{output_dir}/gtk-3.0/assets/*.svg"):
|
||||
subst_text(file, "#5b9bf8", theme_color)
|
||||
subst_text(file, "#3c84f7", theme_color)
|
||||
subst_text(file, "#ffffff", background)
|
||||
subst_text(file, "#2c2c2c", background)
|
||||
subst_text(file, "#3c3c3c", background_alt)
|
||||
|
||||
for file in glob.glob(f"{output_dir}/gtk-4.0/assets/*.svg"):
|
||||
subst_text(file, "#5b9bf8", theme_color)
|
||||
subst_text(file, "#3c84f7", theme_color)
|
||||
subst_text(file, "#ffffff", background)
|
||||
subst_text(file, "#2c2c2c", background)
|
||||
subst_text(file, "#3c3c3c", background_alt)
|
||||
|
||||
if ctx.flavor.dark:
|
||||
subst_text(f"{output_dir}/cinnamon/thumbnail.png", "#2c2c2c", background)
|
||||
subst_text(f"{output_dir}/cinnamon/thumbnail.png", "#5b9bf8", theme_color)
|
||||
|
||||
subst_text(f"{output_dir}/gtk-3.0/thumbnail.png", "#2c2c2c", background)
|
||||
subst_text(f"{output_dir}/gtk-4.0/thumbnail.png", "#2c2c2c", background)
|
||||
|
||||
subst_text(f"{output_dir}/gtk-3.0/thumbnail.png", "#5b9bf8", theme_color)
|
||||
subst_text(f"{output_dir}/gtk-4.0/thumbnail.png", "#5b9bf8", theme_color)
|
||||
else:
|
||||
subst_text(f"{output_dir}/cinnamon/thumbnail.png", "#ffffff", background)
|
||||
subst_text(f"{output_dir}/cinnamon/thumbnail.png", "#f2f2f2", titlebar)
|
||||
subst_text(f"{output_dir}/cinnamon/thumbnail.png", "#3c84f7", theme_color)
|
||||
|
||||
subst_text(f"{output_dir}/gtk-3.0/thumbnail.png", "#f2f2f2", titlebar)
|
||||
subst_text(f"{output_dir}/gtk-3.0/thumbnail.png", "#3c84f7", theme_color)
|
||||
|
||||
subst_text(f"{output_dir}/gtk-4.0/thumbnail.png", "#f2f2f2", titlebar)
|
||||
subst_text(f"{output_dir}/gtk-4.0/thumbnail.png", "#3c84f7", theme_color)
|
||||
|
||||
for file in glob.glob(f"{SRC_DIR}/assets/cinnamon/common-assets/*.svg"):
|
||||
shutil.copy(file, f"{output_dir}/cinnamon/assets")
|
||||
|
||||
for file in glob.glob(f"{SRC_DIR}/assets/cinnamon/assets{ctx.apply_suffix(IS_DARK)}/*.svg"):
|
||||
shutil.copy(file, f"{output_dir}/cinnamon/assets")
|
||||
|
||||
for file in glob.glob(f"{SRC_DIR}/assets/gnome-shell/common-assets/*.svg"):
|
||||
shutil.copy(file, f"{output_dir}/gnome-shell/assets")
|
||||
|
||||
for file in glob.glob(f"{SRC_DIR}/assets/gnome-shell/assets{ctx.apply_suffix(IS_DARK)}/*.svg"):
|
||||
shutil.copy(file, f"{output_dir}/gnome-shell/assets")
|
||||
|
||||
for file in glob.glob(f"{SRC_DIR}/assets/gtk/symbolics/*.svg"):
|
||||
shutil.copy(file, f"{output_dir}/gtk-3.0/assets")
|
||||
shutil.copy(file, f"{output_dir}/gtk-4.0/assets")
|
||||
|
||||
for file in glob.glob(f"{SRC_DIR}/assets/metacity-1/assets{ctx.apply_suffix(IS_WINDOW_NORMAL)}/*.svg"):
|
||||
shutil.copy(file, f"{output_dir}/metacity-1/assets")
|
||||
shutil.copy(
|
||||
f"{SRC_DIR}/assets/metacity-1/thumbnail{ctx.apply_suffix(IS_DARK)}.png",
|
||||
f"{output_dir}/metacity-1/thumbnail.png",
|
||||
)
|
||||
|
||||
xfwm4_assets_root = f"{THIS_DIR}/patches/xfwm4/generated/assets-catppuccin-{ctx.flavor.identifier}"
|
||||
for file in glob.glob(xfwm4_assets_root + '/*'):
|
||||
shutil.copy(file, f"{output_dir}/xfwm4")
|
||||
|
||||
xfwm4_assets = xfwm4_assets_root + "-hdpi/*"
|
||||
for file in glob.glob(xfwm4_assets):
|
||||
shutil.copy(file, f"{output_dir}-hdpi/xfwm4")
|
||||
|
||||
xfwm4_assets = xfwm4_assets_root + "-xhdpi/*"
|
||||
for file in glob.glob(xfwm4_assets):
|
||||
shutil.copy(file, f"{output_dir}-xhdpi/xfwm4")
|
||||
|
||||
|
||||
def zip_dir(path, zip_file):
|
||||
# Ref: https://stackoverflow.com/questions/46229764/python-zip-multiple-directories-into-one-zip-file
|
||||
for root, _, files in os.walk(path):
|
||||
for file in files:
|
||||
zip_file.write(
|
||||
os.path.join(root, file),
|
||||
os.path.relpath(os.path.join(root, file), os.path.join(path, "..")),
|
||||
)
|
||||
|
||||
|
||||
def zip_artifacts(dir_list, zip_name, remove=True):
|
||||
with zipfile.ZipFile(zip_name, "w", zipfile.ZIP_DEFLATED) as zipf:
|
||||
for dir in dir_list:
|
||||
zip_dir(dir, zipf)
|
||||
|
||||
if remove:
|
||||
for dir in dir_list:
|
||||
shutil.rmtree(dir)
|
||||
|
||||
|
||||
def build_theme(ctx: BuildContext):
|
||||
build_info = f"""Build info:
|
||||
build_root: {ctx.build_root}
|
||||
theme_name: {ctx.theme_name}
|
||||
flavor: {ctx.flavor.identifier}
|
||||
accent: {ctx.accent.identifier}
|
||||
size: {ctx.size}
|
||||
tweaks: {ctx.tweaks}"""
|
||||
logger.info(build_info)
|
||||
build(ctx)
|
||||
logger.info(f"Main build complete")
|
||||
|
||||
logger.info("Bundling assets...")
|
||||
make_assets(ctx)
|
||||
logger.info("Asset bundling done")
|
||||
|
||||
if ctx.output_format == "zip":
|
||||
zip_artifacts(
|
||||
[
|
||||
ctx.output_dir(),
|
||||
f"{ctx.output_dir()}-hdpi",
|
||||
f"{ctx.output_dir()}-xhdpi",
|
||||
],
|
||||
f"{ctx.build_root}/{ctx.build_id()}.zip",
|
||||
True,
|
||||
)
|
||||
|
||||
"""
|
||||
if (command -v xfce4-popup-whiskermenu &> /dev/null) && $(sed -i "s|.*menu-opacity=.*|menu-opacity=95|" "$HOME/.config/xfce4/panel/whiskermenu"*".rc" &> /dev/null); then
|
||||
sed -i "s|.*menu-opacity=.*|menu-opacity=95|" "$HOME/.config/xfce4/panel/whiskermenu"*".rc"
|
||||
fi
|
||||
|
||||
if (pgrep xfce4-session &> /dev/null); then
|
||||
xfce4-panel -r
|
||||
fi
|
||||
"""
|
||||
|
||||
|
||||
def apply_colloid_patches():
|
||||
if os.path.isfile("colloid/.patched"):
|
||||
logger.info(
|
||||
'Patches seem to be applied, remove "colloid/.patched" to force application (this may fail)'
|
||||
)
|
||||
return
|
||||
|
||||
logger.info("Applying patches...")
|
||||
# Change into colloid
|
||||
for patch in [
|
||||
"plank-dark.patch",
|
||||
"plank-light.patch",
|
||||
"theme-func.patch",
|
||||
"sass-palette-frappe.patch",
|
||||
"sass-palette-mocha.patch",
|
||||
"sass-palette-latte.patch",
|
||||
"sass-palette-macchiato.patch",
|
||||
"fixes/alt-tab-background-color.patch"
|
||||
]:
|
||||
path = f"./patches/colloid/{patch}"
|
||||
logger.info(f"Applying patch '{patch}', located at '{path}'")
|
||||
subprocess.check_call(["git", "apply", path, "--directory", f"colloid"])
|
||||
|
||||
with open("colloid/.patched", "w") as f:
|
||||
f.write("true")
|
||||
|
||||
logger.info("Patching finished.")
|
||||
|
||||
def parse_args():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument(
|
||||
"flavor",
|
||||
type=str,
|
||||
choices=["mocha", "frappe", "macchiato", "latte"],
|
||||
help="Flavor of the theme to apply.",
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--name",
|
||||
"-n",
|
||||
type=str,
|
||||
default="catppuccin",
|
||||
dest="name",
|
||||
help="Name of the theme to apply.",
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--dest",
|
||||
"-d",
|
||||
type=str,
|
||||
required=True,
|
||||
dest="dest",
|
||||
help="Destination of the files.",
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--accent",
|
||||
"-a",
|
||||
type=str,
|
||||
default="mauve",
|
||||
nargs='+',
|
||||
dest="accents",
|
||||
choices=[
|
||||
"rosewater",
|
||||
"flamingo",
|
||||
"pink",
|
||||
"mauve",
|
||||
"red",
|
||||
"maroon",
|
||||
"peach",
|
||||
"yellow",
|
||||
"green",
|
||||
"teal",
|
||||
"sky",
|
||||
"sapphire",
|
||||
"blue",
|
||||
"lavender",
|
||||
],
|
||||
help="Accent of the theme.",
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--all-accents",
|
||||
help="Whether to build all accents",
|
||||
dest="all_accents",
|
||||
action="store_true",
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--size",
|
||||
"-s",
|
||||
type=str,
|
||||
default="standard",
|
||||
dest="size",
|
||||
choices=["standard", "compact"],
|
||||
help="Size variant of the theme.",
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--tweaks",
|
||||
type=str,
|
||||
default=[],
|
||||
nargs="+",
|
||||
dest="tweaks",
|
||||
choices=["black", "rimless", "normal", "float"],
|
||||
help="Tweaks to apply to the build.",
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--zip",
|
||||
help="Whether to bundle the theme into a zip",
|
||||
type=bool,
|
||||
default=False,
|
||||
action=argparse.BooleanOptionalAction,
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--patch",
|
||||
help="Whether to patch the colloid submodule",
|
||||
type=bool,
|
||||
default=True,
|
||||
action=argparse.BooleanOptionalAction,
|
||||
)
|
||||
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def main():
|
||||
if __name__ == "__main__":
|
||||
git_root = os.path.dirname(os.path.realpath(__file__))
|
||||
args = parse_args()
|
||||
if args.patch:
|
||||
apply_colloid_patches()
|
||||
|
||||
if args.zip:
|
||||
output_format = "zip"
|
||||
else:
|
||||
output_format = "dir"
|
||||
try:
|
||||
start = time.time()
|
||||
execute_build(git_root, args)
|
||||
end = time.time() - start
|
||||
|
||||
tweaks = Tweaks(tweaks=args.tweaks)
|
||||
|
||||
palette = getattr(PALETTE, args.flavor)
|
||||
|
||||
accents = args.accents
|
||||
if args.all_accents:
|
||||
accents = [
|
||||
"rosewater",
|
||||
"flamingo",
|
||||
"pink",
|
||||
"mauve",
|
||||
"red",
|
||||
"maroon",
|
||||
"peach",
|
||||
"yellow",
|
||||
"green",
|
||||
"teal",
|
||||
"sky",
|
||||
"sapphire",
|
||||
"blue",
|
||||
"lavender",
|
||||
]
|
||||
|
||||
for accent in accents:
|
||||
accent = getattr(palette.colors, accent)
|
||||
|
||||
tweaks = Tweaks(tweaks=args.tweaks)
|
||||
|
||||
if args.zip:
|
||||
output_format = "zip"
|
||||
else:
|
||||
output_format = "dir"
|
||||
ctx = BuildContext(
|
||||
build_root=args.dest,
|
||||
theme_name=args.name,
|
||||
flavor=palette,
|
||||
accent=accent,
|
||||
size=args.size,
|
||||
tweaks=tweaks,
|
||||
output_format=output_format,
|
||||
)
|
||||
logger.info("Building temp tweaks file")
|
||||
init_tweaks_temp()
|
||||
logger.info("Inserting gnome-shell imports")
|
||||
gnome_shell_version()
|
||||
logger.info("Building main theme")
|
||||
build_theme(ctx)
|
||||
logger.info(f"Completed {palette.identifier} with {accent.identifier}")
|
||||
|
||||
logger.info("Done!")
|
||||
|
||||
try:
|
||||
main()
|
||||
except Exception as e:
|
||||
logger.info("")
|
||||
logger.info(f"Built in {round(end, 3)}s")
|
||||
except Exception as e:
|
||||
logger.error("Something went wrong when building the theme:", exc_info=e)
|
||||
sys.exit(1)
|
||||
|
14
docker/Dockerfile
Normal file
@@ -0,0 +1,14 @@
|
||||
# This dockerfile generates a container with the needed dependencies to build the theme
|
||||
|
||||
FROM python:alpine
|
||||
|
||||
RUN apk add sassc inkscape optipng
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY requirements.txt .
|
||||
|
||||
RUN pip install --no-cache-dir -r requirements.txt && rm requirements.txt
|
||||
|
||||
# The reason for this is to allow the GH Actions Workflow execute commands within the container
|
||||
CMD ["sleep", "infinity"]
|
83
docker/build.sh
Normal file
@@ -0,0 +1,83 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Default value for custom_version
|
||||
VERSION="no"
|
||||
|
||||
while getopts v:h opt 2>/dev/null; do
|
||||
case "$opt" in
|
||||
v)
|
||||
VERSION=$OPTARG
|
||||
;;
|
||||
h)
|
||||
echo "\
|
||||
Usage: $0 [-v <version>]
|
||||
|
||||
Push script for Catppuccin's GTK docker build image
|
||||
|
||||
-v Custom version to build the image (<your-image-name>:<version>)
|
||||
If you only want to generate the image with tag 'latest' use '-v no'
|
||||
-h Print this help text" >&2
|
||||
exit 0
|
||||
;;
|
||||
?)
|
||||
echo "Usage: $0 [-h]" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
if [ $# -eq 0 ]
|
||||
then
|
||||
echo "Usage: $0 [-h]"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Resolve the absolute path of the script without readlink
|
||||
SCRIPT_PATH="$0"
|
||||
|
||||
# Check if SCRIPT_PATH is a symbolic link
|
||||
while [ -h "$SCRIPT_PATH" ]; do
|
||||
LS=$(ls -ld "$SCRIPT_PATH")
|
||||
LINK=$(expr "$LS" : '.*-> \(.*\)$')
|
||||
if expr "$LINK" : '/.*' > /dev/null; then
|
||||
SCRIPT_PATH="$LINK"
|
||||
else
|
||||
SCRIPT_PATH=$(dirname "$SCRIPT_PATH")/"$LINK"
|
||||
fi
|
||||
done
|
||||
|
||||
# Ensure we have an absolute path
|
||||
case "$SCRIPT_PATH" in
|
||||
/*) ;;
|
||||
*) SCRIPT_PATH="$(pwd)/$SCRIPT_PATH" ;;
|
||||
esac
|
||||
|
||||
# Path to script' dir
|
||||
SCRIPT_DIR=$(cd "$(dirname "$SCRIPT_PATH")" && pwd)
|
||||
|
||||
# Path to the Dockerfile
|
||||
DOCKERFILE_PATH="$SCRIPT_DIR/Dockerfile"
|
||||
|
||||
# Docker variables
|
||||
IMAGE_NAME="ghcr.io/catppuccin/gtk"
|
||||
|
||||
# Detect podman
|
||||
if command -v podman > /dev/null 2>&1; then
|
||||
CONTAINER_TOOL="podman"
|
||||
elif command -v docker > /dev/null 2>&1; then
|
||||
CONTAINER_TOOL="docker"
|
||||
else
|
||||
echo "Error: Neither podman nor docker is installed."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Clean previous generated images
|
||||
$CONTAINER_TOOL image rm "$IMAGE_NAME:latest" 2> /dev/null
|
||||
$CONTAINER_TOOL image rm "$IMAGE_NAME:$VERSION" 2> /dev/null
|
||||
|
||||
# Build the Docker image with latest tag
|
||||
$CONTAINER_TOOL build -t "$IMAGE_NAME:latest" -f "$DOCKERFILE_PATH" "$SCRIPT_DIR/.."
|
||||
|
||||
# Execute docker tag command if VERSION is not "no"
|
||||
if [ "$VERSION" != "no" ]; then
|
||||
$CONTAINER_TOOL tag "$IMAGE_NAME:latest" "$IMAGE_NAME:$VERSION"
|
||||
fi
|
66
docker/push.sh
Normal file
@@ -0,0 +1,66 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Default value for parameters
|
||||
VERSION="no"
|
||||
USERNAME="no"
|
||||
PASSWORD="no"
|
||||
|
||||
while getopts u:p:v:h opt 2>/dev/null; do
|
||||
case "$opt" in
|
||||
v)
|
||||
VERSION=$OPTARG
|
||||
;;
|
||||
u)
|
||||
USERNAME=$OPTARG
|
||||
;;
|
||||
p)
|
||||
PASSWORD=$OPTARG
|
||||
;;
|
||||
h)
|
||||
echo "\
|
||||
Usage: $0 [-v <version> | -u [your-github-username] | -p [your-github-password]]
|
||||
|
||||
Push script for Catppuccin's GTK docker build image
|
||||
|
||||
-v Custom version to push the image (<your-image-name>:<version>)
|
||||
-u Your GitHub username that will be used to log into GHCR
|
||||
-p Your GitHub password that will be used to log into GHCR
|
||||
-h Print this help text" >&2
|
||||
exit 0
|
||||
;;
|
||||
?)
|
||||
echo "Usage: $0 [-h]" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
if [ $# -eq 0 ]
|
||||
then
|
||||
echo "Usage: $0 [-h]"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
# Detect podman
|
||||
if command -v podman > /dev/null 2>&1; then
|
||||
CONTAINER_TOOL="podman"
|
||||
elif command -v docker > /dev/null 2>&1; then
|
||||
CONTAINER_TOOL="docker"
|
||||
else
|
||||
echo "Error: Neither podman nor docker is installed."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Docker variables
|
||||
IMAGE_NAME="ghcr.io/catppuccin/gtk"
|
||||
|
||||
# Log into ghcr
|
||||
$CONTAINER_TOOL login ghcr.io -u $USERNAME --password $PASSWORD
|
||||
|
||||
# Push docker image with latest tag
|
||||
$CONTAINER_TOOL push "$IMAGE_NAME:latest"
|
||||
|
||||
# Execute docker push for specific version if VERSION is not "no"
|
||||
if [ "$VERSION" != "no" ]; then
|
||||
$CONTAINER_TOOL push "$IMAGE_NAME:$VERSION"
|
||||
fi
|
@@ -6,6 +6,18 @@ Information regarding the architecture of the project can be found [in the ARCHI
|
||||
- All the [requirements for building](#building)
|
||||
- `whiskers`, optionally, from [catppuccin/toolbox](https://github.com/catppuccin/toolbox/tree/main/whiskers#installation)
|
||||
|
||||
### Project structure
|
||||
|
||||
`sources/` contains all of the source files needed for the project to build, including the Colloid submodule.
|
||||
It also contains our patches for Colloid, alongside the core build system implemented by us to replace the one from Colloid.
|
||||
|
||||
`build.py` is the entrypoint to the build system, placed at the root for convenience. The plumbing this utilizes is in
|
||||
`sources/build`.
|
||||
|
||||
`install.py` is our officially supported install script, which will automate the process of pulling the release, extracting it,
|
||||
and optionally adding symlinks for GTK-4.0 support. This script intentionally has no dependencies other than Python 3 itself.
|
||||
This keeps the end user experience simple and reproducible. Do not add external dependencies to this script.
|
||||
|
||||
### Patching colloid
|
||||
> [!TIP]
|
||||
> If you need to change the patches, reset the submodule and rerun the build script.
|
10
install.py
@@ -1,11 +1,15 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import os, zipfile, argparse, logging, io
|
||||
import os
|
||||
import zipfile
|
||||
import argparse
|
||||
import logging
|
||||
import io
|
||||
|
||||
from typing import Optional
|
||||
from pathlib import Path
|
||||
from dataclasses import dataclass
|
||||
from urllib.request import urlopen, Request
|
||||
from urllib.parse import urlparse
|
||||
|
||||
logger = logging.getLogger("catppuccin-gtk")
|
||||
logger.setLevel(logging.DEBUG)
|
||||
@@ -160,6 +164,7 @@ def install(ctx: InstallContext):
|
||||
if ctx.link:
|
||||
add_libadwaita_links(ctx)
|
||||
|
||||
|
||||
def install_from_artifact(ctx: InstallContext, artifact_path: Path):
|
||||
# Working from a pull request, special case it
|
||||
logger.info(f"Extracting artifact from '{artifact_path}'")
|
||||
@@ -189,6 +194,7 @@ def install_from_artifact(ctx: InstallContext, artifact_path: Path):
|
||||
add_libadwaita_links(ctx, True)
|
||||
logger.info("Links added")
|
||||
|
||||
|
||||
def main():
|
||||
args = parse_args()
|
||||
|
||||
|
74
sources/build/__init__.py
Normal file
@@ -0,0 +1,74 @@
|
||||
from argparse import Namespace
|
||||
import shutil
|
||||
|
||||
from .patches import apply_colloid_patches
|
||||
from .theme import build_with_context, gnome_shell_version
|
||||
from .utils import init_tweaks_temp
|
||||
from .context import Tweaks, BuildContext
|
||||
from .logger import logger
|
||||
from catppuccin import PALETTE
|
||||
|
||||
|
||||
def execute_build(git_root: str, args: Namespace):
|
||||
|
||||
colloid_dir = f"{git_root}/sources/colloid"
|
||||
colloid_tmp_dir = f"{git_root}/.tmp/colloid-tmp-{args.flavor}"
|
||||
shutil.copytree(colloid_dir, colloid_tmp_dir)
|
||||
src_dir = colloid_tmp_dir + "/src"
|
||||
|
||||
tweaks = Tweaks(tweaks=args.tweaks)
|
||||
palette = getattr(PALETTE, args.flavor)
|
||||
output_format = "zip" if args.zip else "dir"
|
||||
|
||||
if args.patch:
|
||||
patch_dir = git_root + "/sources/patches/colloid/"
|
||||
apply_colloid_patches(colloid_tmp_dir, patch_dir)
|
||||
|
||||
accents = args.accents
|
||||
if args.all_accents:
|
||||
accents = [
|
||||
"rosewater",
|
||||
"flamingo",
|
||||
"pink",
|
||||
"mauve",
|
||||
"red",
|
||||
"maroon",
|
||||
"peach",
|
||||
"yellow",
|
||||
"green",
|
||||
"teal",
|
||||
"sky",
|
||||
"sapphire",
|
||||
"blue",
|
||||
"lavender",
|
||||
]
|
||||
|
||||
for accent in accents:
|
||||
accent = getattr(palette.colors, accent)
|
||||
|
||||
ctx = BuildContext(
|
||||
output_root=args.dest,
|
||||
colloid_src_dir=src_dir,
|
||||
git_root=git_root,
|
||||
theme_name=args.name,
|
||||
flavor=palette,
|
||||
accent=accent,
|
||||
size=args.size,
|
||||
tweaks=tweaks,
|
||||
output_format=output_format,
|
||||
)
|
||||
|
||||
logger.info("Building temp tweaks file")
|
||||
init_tweaks_temp(src_dir)
|
||||
|
||||
logger.info("Inserting gnome-shell imports")
|
||||
gnome_shell_version(src_dir)
|
||||
|
||||
logger.info("Building main theme")
|
||||
build_with_context(ctx)
|
||||
|
||||
logger.info(f"Completed {palette.identifier} with {accent.identifier}")
|
||||
print()
|
||||
|
||||
shutil.rmtree(colloid_tmp_dir)
|
||||
logger.info("Done!")
|
100
sources/build/args.py
Normal file
@@ -0,0 +1,100 @@
|
||||
import argparse
|
||||
|
||||
|
||||
def parse_args():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument(
|
||||
"flavor",
|
||||
type=str,
|
||||
choices=["mocha", "frappe", "macchiato", "latte"],
|
||||
help="Flavor of the theme to apply.",
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--name",
|
||||
"-n",
|
||||
type=str,
|
||||
default="catppuccin",
|
||||
dest="name",
|
||||
help="Name of the theme to apply.",
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--dest",
|
||||
"-d",
|
||||
type=str,
|
||||
required=True,
|
||||
dest="dest",
|
||||
help="Destination of the files.",
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--accent",
|
||||
"-a",
|
||||
type=str,
|
||||
default="mauve",
|
||||
nargs="+",
|
||||
dest="accents",
|
||||
choices=[
|
||||
"rosewater",
|
||||
"flamingo",
|
||||
"pink",
|
||||
"mauve",
|
||||
"red",
|
||||
"maroon",
|
||||
"peach",
|
||||
"yellow",
|
||||
"green",
|
||||
"teal",
|
||||
"sky",
|
||||
"sapphire",
|
||||
"blue",
|
||||
"lavender",
|
||||
],
|
||||
help="Accent of the theme.",
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--all-accents",
|
||||
help="Whether to build all accents",
|
||||
dest="all_accents",
|
||||
action="store_true",
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--size",
|
||||
"-s",
|
||||
type=str,
|
||||
default="standard",
|
||||
dest="size",
|
||||
choices=["standard", "compact"],
|
||||
help="Size variant of the theme.",
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--tweaks",
|
||||
type=str,
|
||||
default=[],
|
||||
nargs="+",
|
||||
dest="tweaks",
|
||||
choices=["black", "rimless", "normal", "float"],
|
||||
help="Tweaks to apply to the build.",
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--zip",
|
||||
help="Whether to bundle the theme into a zip",
|
||||
type=bool,
|
||||
default=False,
|
||||
action=argparse.BooleanOptionalAction,
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--patch",
|
||||
help="Whether to patch the colloid submodule",
|
||||
type=bool,
|
||||
default=True,
|
||||
action=argparse.BooleanOptionalAction,
|
||||
)
|
||||
|
||||
return parser.parse_args()
|
69
sources/build/context.py
Normal file
@@ -0,0 +1,69 @@
|
||||
from dataclasses import dataclass
|
||||
from typing import Any, Literal, List
|
||||
from catppuccin.models import Flavor, Color
|
||||
from .utils import find_and_replace, Subsitution
|
||||
|
||||
|
||||
@dataclass
|
||||
class Tweaks:
|
||||
tweaks: List[str]
|
||||
|
||||
def has(self, tweak: str) -> bool:
|
||||
return tweak in self.tweaks
|
||||
|
||||
def id(self) -> str:
|
||||
return ",".join(self.tweaks)
|
||||
|
||||
|
||||
@dataclass
|
||||
class Suffix:
|
||||
true_value: str
|
||||
test: Any
|
||||
false_value: str = ""
|
||||
|
||||
|
||||
@dataclass
|
||||
class BuildContext:
|
||||
# The src dir of the Colloid copy to operate on
|
||||
colloid_src_dir: str
|
||||
|
||||
# The root of the project
|
||||
git_root: str
|
||||
|
||||
# The root of the output dir (as specified by --dest if given)
|
||||
output_root: str
|
||||
|
||||
output_format: Literal["zip"] | Literal["dir"]
|
||||
|
||||
theme_name: str
|
||||
flavor: Flavor
|
||||
accent: Color
|
||||
size: Literal["standard"] | Literal["compact"]
|
||||
tweaks: Tweaks
|
||||
|
||||
def output_dir(self) -> str:
|
||||
return f"{self.output_root}/{self.build_id()}"
|
||||
|
||||
def build_id(self) -> str:
|
||||
return f"{self.theme_name}-{self.flavor.identifier}-{self.accent.identifier}-{self.size}+{self.tweaks.id() or 'default'}"
|
||||
|
||||
def apply_suffix(self, suffix: Suffix) -> str:
|
||||
if suffix.test(self):
|
||||
return suffix.true_value
|
||||
else:
|
||||
return suffix.false_value
|
||||
|
||||
def apply_tweak(self, key, default, value):
|
||||
find_and_replace(
|
||||
f"{self.colloid_src_dir}/sass/_tweaks-temp.scss",
|
||||
Subsitution(find=f"\\${key}: {default}", replace=f"${key}: {value}"),
|
||||
)
|
||||
|
||||
IS_DARK = Suffix(true_value="-Dark", test=lambda ctx: ctx.flavor.dark)
|
||||
IS_LIGHT = Suffix(true_value="-Light", test=lambda ctx: not ctx.flavor.dark)
|
||||
IS_WINDOW_NORMAL = Suffix(
|
||||
true_value="-Normal", test=lambda ctx: ctx.tweaks.has("normal")
|
||||
)
|
||||
DARK_LIGHT = Suffix(
|
||||
true_value="-Dark", false_value="-Light", test=lambda ctx: ctx.flavor.dark
|
||||
)
|
9
sources/build/logger.py
Normal file
@@ -0,0 +1,9 @@
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger("catppuccin-gtk")
|
||||
|
||||
logger.setLevel(logging.DEBUG)
|
||||
ch = logging.StreamHandler()
|
||||
formatter = logging.Formatter("[%(name)s] [%(levelname)s] - %(message)s")
|
||||
ch.setFormatter(formatter)
|
||||
logger.addHandler(ch)
|
35
sources/build/patches.py
Normal file
@@ -0,0 +1,35 @@
|
||||
import os
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
from .logger import logger
|
||||
|
||||
|
||||
def apply_colloid_patches(colloid_dir, patch_dir):
|
||||
colloid_dir = Path(colloid_dir).relative_to(os.getcwd())
|
||||
if os.path.isfile(colloid_dir / ".patched"):
|
||||
logger.info(
|
||||
f'Patches seem to be applied, remove "{colloid_dir}/.patched" to force application (this may fail)'
|
||||
)
|
||||
return
|
||||
|
||||
logger.info("Applying patches...")
|
||||
# Change into colloid
|
||||
for patch in [
|
||||
"plank-dark.patch",
|
||||
"plank-light.patch",
|
||||
"sass-palette-frappe.patch",
|
||||
"sass-palette-mocha.patch",
|
||||
"sass-palette-latte.patch",
|
||||
"sass-palette-macchiato.patch",
|
||||
"theme-func.patch",
|
||||
]:
|
||||
path = (Path(patch_dir) / patch).relative_to(os.getcwd())
|
||||
logger.info(f"Applying patch '{patch}', located at '{path}'")
|
||||
subprocess.check_call(
|
||||
["git", "apply", str(path), "--directory", str(colloid_dir)]
|
||||
)
|
||||
|
||||
with open(colloid_dir / ".patched", "w") as f:
|
||||
f.write("true")
|
||||
|
||||
logger.info("Patching finished.")
|
390
sources/build/theme.py
Normal file
@@ -0,0 +1,390 @@
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import glob
|
||||
import zipfile
|
||||
from .logger import logger
|
||||
from .utils import find_and_replace, Subsitution
|
||||
from .context import BuildContext, IS_DARK, IS_LIGHT, IS_WINDOW_NORMAL, DARK_LIGHT
|
||||
|
||||
|
||||
def apply_tweaks(ctx: BuildContext):
|
||||
ctx.apply_tweak("theme", "'default'", f"'{ctx.accent.identifier}'")
|
||||
|
||||
if ctx.size == "compact":
|
||||
ctx.apply_tweak("compact", "'false'", "'true'")
|
||||
|
||||
find_and_replace(
|
||||
f"{ctx.colloid_src_dir}/sass/_tweaks-temp.scss",
|
||||
Subsitution(
|
||||
find="@import 'color-palette-default';",
|
||||
replace=f"@import 'color-palette-catppuccin-{ctx.flavor.identifier}';",
|
||||
),
|
||||
)
|
||||
ctx.apply_tweak("colorscheme", "'default'", "'catppuccin'")
|
||||
|
||||
if ctx.tweaks.has("black"):
|
||||
ctx.apply_tweak("blackness", "'false'", "'true'")
|
||||
|
||||
if ctx.tweaks.has("rimless"):
|
||||
ctx.apply_tweak("rimless", "'false'", "'true'")
|
||||
|
||||
if ctx.tweaks.has("normal"):
|
||||
ctx.apply_tweak("window_button", "'mac'", "'normal'")
|
||||
|
||||
if ctx.tweaks.has("float"):
|
||||
ctx.apply_tweak("float", "'false'", "'true'")
|
||||
|
||||
|
||||
SASSC_OPT = ["-M", "-t", "expanded"]
|
||||
|
||||
|
||||
def compile_sass(src: str, dest: str) -> subprocess.Popen:
|
||||
return subprocess.Popen(["sassc", *SASSC_OPT, src, dest])
|
||||
|
||||
|
||||
def execute_build(ctx: BuildContext):
|
||||
src_dir = ctx.colloid_src_dir
|
||||
output_dir = ctx.output_dir()
|
||||
|
||||
logger.info(f"Building into '{output_dir}'...")
|
||||
|
||||
apply_tweaks(ctx)
|
||||
|
||||
os.makedirs(output_dir, exist_ok=True)
|
||||
with open(f"{output_dir}/index.theme", "w") as file:
|
||||
file.write("[Desktop Entry]\n")
|
||||
file.write("Type=X-GNOME-Metatheme\n")
|
||||
file.write(f"Name={ctx.build_id()}\n")
|
||||
file.write("Comment=An Flat Gtk+ theme based on Elegant Design\n")
|
||||
file.write("Encoding=UTF-8\n")
|
||||
file.write("\n")
|
||||
file.write("[X-GNOME-Metatheme]\n")
|
||||
file.write(f"GtkTheme={ctx.build_id()}\n")
|
||||
file.write(f"MetacityTheme={ctx.build_id()}\n")
|
||||
file.write(f"IconTheme=Tela-circle{ctx.apply_suffix(IS_DARK)}\n")
|
||||
file.write(f"CursorTheme={ctx.flavor.name}-cursors\n")
|
||||
file.write("ButtonLayout=close,minimize,maximize:menu\n")
|
||||
|
||||
sassc_tasks = []
|
||||
|
||||
os.makedirs(f"{output_dir}/gnome-shell", exist_ok=True)
|
||||
shutil.copyfile(
|
||||
f"{src_dir}/main/gnome-shell/pad-osd.css",
|
||||
f"{output_dir}/gnome-shell/pad-osd.css",
|
||||
)
|
||||
|
||||
sassc_tasks.append(
|
||||
compile_sass(
|
||||
f"{src_dir}/main/gnome-shell/gnome-shell{ctx.apply_suffix(DARK_LIGHT)}.scss",
|
||||
f"{output_dir}/gnome-shell/gnome-shell.css",
|
||||
)
|
||||
)
|
||||
|
||||
os.makedirs(f"{output_dir}/gtk-3.0", exist_ok=True)
|
||||
sassc_tasks.append(
|
||||
compile_sass(
|
||||
f"{src_dir}/main/gtk-3.0/gtk{ctx.apply_suffix(DARK_LIGHT)}.scss",
|
||||
f"{output_dir}/gtk-3.0/gtk.css",
|
||||
)
|
||||
)
|
||||
sassc_tasks.append(
|
||||
compile_sass(
|
||||
f"{src_dir}/main/gtk-3.0/gtk-Dark.scss",
|
||||
f"{output_dir}/gtk-3.0/gtk-dark.css",
|
||||
)
|
||||
)
|
||||
|
||||
os.makedirs(f"{output_dir}/gtk-4.0", exist_ok=True)
|
||||
sassc_tasks.append(
|
||||
compile_sass(
|
||||
f"{src_dir}/main/gtk-4.0/gtk{ctx.apply_suffix(DARK_LIGHT)}.scss",
|
||||
f"{output_dir}/gtk-4.0/gtk.css",
|
||||
)
|
||||
)
|
||||
sassc_tasks.append(
|
||||
compile_sass(
|
||||
f"{src_dir}/main/gtk-4.0/gtk-Dark.scss",
|
||||
f"{output_dir}/gtk-4.0/gtk-dark.css",
|
||||
)
|
||||
)
|
||||
|
||||
os.makedirs(f"{output_dir}/cinnamon", exist_ok=True)
|
||||
sassc_tasks.append(
|
||||
compile_sass(
|
||||
f"{src_dir}/main/cinnamon/cinnamon{ctx.apply_suffix(DARK_LIGHT)}.scss",
|
||||
f"{output_dir}/cinnamon/cinnamon.css",
|
||||
)
|
||||
)
|
||||
|
||||
for task in sassc_tasks:
|
||||
task.wait()
|
||||
|
||||
os.makedirs(f"{output_dir}/metacity-1", exist_ok=True)
|
||||
shutil.copyfile(
|
||||
f"{src_dir}/main/metacity-1/metacity-theme-3{ctx.apply_suffix(IS_WINDOW_NORMAL)}.xml",
|
||||
f"{output_dir}/metacity-1/metacity-theme-3.xml",
|
||||
)
|
||||
|
||||
os.makedirs(f"{output_dir}/xfwm4", exist_ok=True)
|
||||
shutil.copyfile(
|
||||
f"{src_dir}/main/xfwm4/themerc{ctx.apply_suffix(IS_LIGHT)}",
|
||||
f"{output_dir}/xfwm4/themerc",
|
||||
)
|
||||
|
||||
os.makedirs(f"{output_dir}-hdpi/xfwm4", exist_ok=True)
|
||||
shutil.copyfile(
|
||||
f"{src_dir}/main/xfwm4/themerc{ctx.apply_suffix(IS_LIGHT)}",
|
||||
f"{output_dir}-hdpi/xfwm4/themerc",
|
||||
)
|
||||
find_and_replace(
|
||||
f"{output_dir}-hdpi/xfwm4/themerc",
|
||||
Subsitution(find="button_offset=6", replace="button_offset=9"),
|
||||
)
|
||||
|
||||
os.makedirs(f"{output_dir}-xhdpi/xfwm4", exist_ok=True)
|
||||
shutil.copyfile(
|
||||
f"{src_dir}/main/xfwm4/themerc{ctx.apply_suffix(IS_LIGHT)}",
|
||||
f"{output_dir}-xhdpi/xfwm4/themerc",
|
||||
)
|
||||
|
||||
find_and_replace(
|
||||
f"{output_dir}-xhdpi/xfwm4/themerc",
|
||||
Subsitution(find="button_offset=6", replace="button_offset=12"),
|
||||
)
|
||||
|
||||
if not ctx.flavor.dark:
|
||||
shutil.copytree(
|
||||
f"{src_dir}/main/plank/theme-Light-Catppuccin/",
|
||||
f"{output_dir}/plank",
|
||||
dirs_exist_ok=True,
|
||||
)
|
||||
else:
|
||||
shutil.copytree(
|
||||
f"{src_dir}/main/plank/theme-Dark-Catppuccin/",
|
||||
f"{output_dir}/plank",
|
||||
dirs_exist_ok=True,
|
||||
)
|
||||
|
||||
|
||||
def make_assets(ctx: BuildContext):
|
||||
output_dir = ctx.output_dir()
|
||||
src_dir = ctx.colloid_src_dir
|
||||
|
||||
os.makedirs(f"{output_dir}/cinnamon/assets", exist_ok=True)
|
||||
for file in glob.glob(f"{src_dir}/assets/cinnamon/theme/*.svg"):
|
||||
shutil.copy(file, f"{output_dir}/cinnamon/assets")
|
||||
shutil.copy(
|
||||
f"{src_dir}/assets/cinnamon/thumbnail{ctx.apply_suffix(DARK_LIGHT)}.svg",
|
||||
f"{output_dir}/cinnamon/thumbnail.png",
|
||||
)
|
||||
|
||||
os.makedirs(f"{output_dir}/gnome-shell/assets", exist_ok=True)
|
||||
for file in glob.glob(f"{src_dir}/assets/gnome-shell/theme/*.svg"):
|
||||
shutil.copy(file, f"{output_dir}/gnome-shell/assets")
|
||||
|
||||
shutil.copytree(
|
||||
f"{src_dir}/assets/gtk/assets",
|
||||
f"{output_dir}/gtk-3.0/assets",
|
||||
dirs_exist_ok=True,
|
||||
)
|
||||
shutil.copytree(
|
||||
f"{src_dir}/assets/gtk/assets",
|
||||
f"{output_dir}/gtk-4.0/assets",
|
||||
dirs_exist_ok=True,
|
||||
)
|
||||
shutil.copyfile(
|
||||
f"{src_dir}/assets/gtk/thumbnail{ctx.apply_suffix(IS_DARK)}.svg",
|
||||
f"{output_dir}/gtk-3.0/thumbnail.png",
|
||||
)
|
||||
shutil.copyfile(
|
||||
f"{src_dir}/assets/gtk/thumbnail{ctx.apply_suffix(IS_DARK)}.svg",
|
||||
f"{output_dir}/gtk-4.0/thumbnail.png",
|
||||
)
|
||||
|
||||
theme_color = ctx.accent.hex
|
||||
|
||||
palette = ctx.flavor.colors
|
||||
background = palette.base.hex
|
||||
background_alt = palette.mantle.hex
|
||||
titlebar = palette.overlay0.hex
|
||||
|
||||
for file in glob.glob(f"{output_dir}/cinnamon/assets/*.svg"):
|
||||
find_and_replace(
|
||||
file,
|
||||
Subsitution(find="#5b9bf8", replace=theme_color),
|
||||
Subsitution(find="#3c84f7", replace=theme_color),
|
||||
)
|
||||
|
||||
for file in glob.glob(f"{output_dir}/gnome-shell/assets/*.svg"):
|
||||
find_and_replace(
|
||||
file,
|
||||
Subsitution(find="#5b9bf8", replace=theme_color),
|
||||
Subsitution(find="#3c84f7", replace=theme_color),
|
||||
)
|
||||
|
||||
for file in glob.glob(f"{output_dir}/gtk-3.0/assets/*.svg"):
|
||||
find_and_replace(
|
||||
file,
|
||||
Subsitution(find="#5b9bf8", replace=theme_color),
|
||||
Subsitution(find="#3c84f7", replace=theme_color),
|
||||
Subsitution(find="#ffffff", replace=background),
|
||||
Subsitution(find="#2c2c2c", replace=background),
|
||||
Subsitution(find="#3c3c3c", replace=background_alt),
|
||||
)
|
||||
|
||||
for file in glob.glob(f"{output_dir}/gtk-4.0/assets/*.svg"):
|
||||
find_and_replace(
|
||||
file,
|
||||
Subsitution(find="#5b9bf8", replace=theme_color),
|
||||
Subsitution(find="#3c84f7", replace=theme_color),
|
||||
Subsitution(find="#ffffff", replace=background),
|
||||
Subsitution(find="#2c2c2c", replace=background),
|
||||
Subsitution(find="#3c3c3c", replace=background_alt),
|
||||
)
|
||||
|
||||
if ctx.flavor.dark:
|
||||
find_and_replace(
|
||||
f"{output_dir}/cinnamon/thumbnail.png",
|
||||
Subsitution(find="#2c2c2c", replace=background),
|
||||
Subsitution(find="#5b9bf8", replace=theme_color),
|
||||
)
|
||||
|
||||
find_and_replace(
|
||||
f"{output_dir}/gtk-3.0/thumbnail.png",
|
||||
Subsitution(find="#5b9bf8", replace=theme_color),
|
||||
Subsitution(find="#2c2c2c", replace=background),
|
||||
)
|
||||
|
||||
find_and_replace(
|
||||
f"{output_dir}/gtk-4.0/thumbnail.png",
|
||||
Subsitution(find="#5b9bf8", replace=theme_color),
|
||||
Subsitution(find="#2c2c2c", replace=background),
|
||||
)
|
||||
else:
|
||||
find_and_replace(
|
||||
f"{output_dir}/cinnamon/thumbnail.png",
|
||||
Subsitution(find="#ffffff", replace=background),
|
||||
Subsitution(find="#f2f2f2", replace=titlebar),
|
||||
Subsitution(find="#3c84f7", replace=theme_color),
|
||||
)
|
||||
|
||||
find_and_replace(
|
||||
f"{output_dir}/gtk-3.0/thumbnail.png",
|
||||
Subsitution(find="#f2f2f2", replace=titlebar),
|
||||
Subsitution(find="#3c84f7", replace=theme_color),
|
||||
)
|
||||
|
||||
find_and_replace(
|
||||
f"{output_dir}/gtk-4.0/thumbnail.png",
|
||||
Subsitution(find="#f2f2f2", replace=titlebar),
|
||||
Subsitution(find="#3c84f7", replace=theme_color),
|
||||
)
|
||||
|
||||
for file in glob.glob(f"{src_dir}/assets/cinnamon/common-assets/*.svg"):
|
||||
shutil.copy(file, f"{output_dir}/cinnamon/assets")
|
||||
|
||||
for file in glob.glob(
|
||||
f"{src_dir}/assets/cinnamon/assets{ctx.apply_suffix(IS_DARK)}/*.svg"
|
||||
):
|
||||
shutil.copy(file, f"{output_dir}/cinnamon/assets")
|
||||
|
||||
for file in glob.glob(f"{src_dir}/assets/gnome-shell/common-assets/*.svg"):
|
||||
shutil.copy(file, f"{output_dir}/gnome-shell/assets")
|
||||
|
||||
for file in glob.glob(
|
||||
f"{src_dir}/assets/gnome-shell/assets{ctx.apply_suffix(IS_DARK)}/*.svg"
|
||||
):
|
||||
shutil.copy(file, f"{output_dir}/gnome-shell/assets")
|
||||
|
||||
for file in glob.glob(f"{src_dir}/assets/gtk/symbolics/*.svg"):
|
||||
shutil.copy(file, f"{output_dir}/gtk-3.0/assets")
|
||||
shutil.copy(file, f"{output_dir}/gtk-4.0/assets")
|
||||
|
||||
for file in glob.glob(
|
||||
f"{src_dir}/assets/metacity-1/assets{ctx.apply_suffix(IS_WINDOW_NORMAL)}/*.svg"
|
||||
):
|
||||
shutil.copy(file, f"{output_dir}/metacity-1/assets")
|
||||
shutil.copy(
|
||||
f"{src_dir}/assets/metacity-1/thumbnail{ctx.apply_suffix(IS_DARK)}.png",
|
||||
f"{output_dir}/metacity-1/thumbnail.png",
|
||||
)
|
||||
|
||||
xfwm4_assets = f"{ctx.git_root}/patches/xfwm4/generated/assets-catppuccin-{ctx.flavor.identifier}"
|
||||
for file in glob.glob(xfwm4_assets + "/*"):
|
||||
shutil.copy(file, f"{output_dir}/xfwm4")
|
||||
|
||||
xfwm4_assets = xfwm4_assets + "-hdpi/*"
|
||||
for file in glob.glob(xfwm4_assets):
|
||||
shutil.copy(file, f"{output_dir}-hdpi/xfwm4")
|
||||
|
||||
xfwm4_assets = xfwm4_assets + "-xhdpi/*"
|
||||
for file in glob.glob(xfwm4_assets):
|
||||
shutil.copy(file, f"{output_dir}-xhdpi/xfwm4")
|
||||
|
||||
|
||||
def zip_dir(path, zip_file):
|
||||
for root, _, files in os.walk(path):
|
||||
for file in files:
|
||||
zip_file.write(
|
||||
os.path.join(root, file),
|
||||
os.path.relpath(os.path.join(root, file), os.path.join(path, "..")),
|
||||
)
|
||||
|
||||
|
||||
def zip_artifacts(dir_list, zip_name, remove=True):
|
||||
with zipfile.ZipFile(zip_name, "w", zipfile.ZIP_DEFLATED) as zipf:
|
||||
for dir in dir_list:
|
||||
zip_dir(dir, zipf)
|
||||
|
||||
if remove:
|
||||
for dir in dir_list:
|
||||
shutil.rmtree(dir)
|
||||
|
||||
|
||||
def build_with_context(ctx: BuildContext):
|
||||
build_info = f"""Build info:
|
||||
build_root: {ctx.output_root}
|
||||
src_root: {ctx.colloid_src_dir}
|
||||
theme_name: {ctx.theme_name}
|
||||
flavor: {ctx.flavor.identifier}
|
||||
accent: {ctx.accent.identifier}
|
||||
size: {ctx.size}
|
||||
tweaks: {ctx.tweaks}"""
|
||||
logger.info(build_info)
|
||||
|
||||
execute_build(ctx)
|
||||
logger.info("Main build complete")
|
||||
|
||||
logger.info("Bundling assets...")
|
||||
make_assets(ctx)
|
||||
logger.info("Asset bundling done")
|
||||
|
||||
if ctx.output_format == "zip":
|
||||
zip_artifacts(
|
||||
[
|
||||
ctx.output_dir(),
|
||||
f"{ctx.output_dir()}-hdpi",
|
||||
f"{ctx.output_dir()}-xhdpi",
|
||||
],
|
||||
f"{ctx.output_root}/{ctx.build_id()}.zip",
|
||||
True,
|
||||
)
|
||||
|
||||
|
||||
def gnome_shell_version(src_dir):
|
||||
# Hardcoded here, Colloid checks for this on end user machines
|
||||
# but we cannot do that. Old build system would've resulted in this too.
|
||||
gs_version = "46-0"
|
||||
|
||||
shutil.copyfile(
|
||||
f"{src_dir}/sass/gnome-shell/_common.scss",
|
||||
f"{src_dir}/sass/gnome-shell/_common-temp.scss",
|
||||
)
|
||||
find_and_replace(
|
||||
f"{src_dir}/sass/gnome-shell/_common-temp.scss",
|
||||
Subsitution(
|
||||
find="@import 'widgets-40-0';",
|
||||
replace=f"@import 'widgets-{gs_version}';",
|
||||
),
|
||||
)
|
23
sources/build/utils.py
Normal file
@@ -0,0 +1,23 @@
|
||||
import re
|
||||
import shutil
|
||||
from dataclasses import dataclass
|
||||
|
||||
|
||||
@dataclass
|
||||
class Subsitution:
|
||||
find: str
|
||||
replace: str
|
||||
|
||||
|
||||
def find_and_replace(path: str, *subs: Subsitution):
|
||||
with open(path, "r+") as f:
|
||||
content = f.read()
|
||||
f.seek(0)
|
||||
f.truncate()
|
||||
for sub in subs:
|
||||
content = re.sub(sub.find, sub.replace, content)
|
||||
f.write(content)
|
||||
|
||||
|
||||
def init_tweaks_temp(src_dir):
|
||||
shutil.copyfile(f"{src_dir}/sass/_tweaks.scss", f"{src_dir}/sass/_tweaks-temp.scss")
|
Before Width: | Height: | Size: 57 KiB After Width: | Height: | Size: 57 KiB |
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 47 KiB |
Before Width: | Height: | Size: 57 KiB After Width: | Height: | Size: 57 KiB |
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 46 KiB |
@@ -2,7 +2,11 @@ from typing import List
|
||||
from catppuccin import PALETTE
|
||||
from catppuccin.models import Flavor
|
||||
|
||||
import re, os, shutil, subprocess, time
|
||||
import re
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import time
|
||||
from dataclasses import dataclass
|
||||
|
||||
THIS_DIR = os.path.dirname(os.path.realpath(__file__))
|
||||
@@ -83,9 +87,9 @@ def generate_for_flavor(flavor: Flavor):
|
||||
# Setup the palette
|
||||
palette = flavor.colors
|
||||
|
||||
close_color=f'#{palette.red.hex}'
|
||||
max_color=f'#{palette.green.hex}'
|
||||
min_color=f'#{palette.yellow.hex}'
|
||||
close_color = f"#{palette.red.hex}"
|
||||
max_color = f"#{palette.green.hex}"
|
||||
min_color = f"#{palette.yellow.hex}"
|
||||
|
||||
# We expand the source assets into the 4 flavors, but need to map between
|
||||
# Their definition of dark and ours. This means that latte will get the -light assets
|
||||
@@ -187,6 +191,7 @@ screen_to_dpi = {
|
||||
"-xhdpi": "192",
|
||||
}
|
||||
|
||||
|
||||
def render_for_screen(state: RenderState, flavor: Flavor, screen: str, ident: str):
|
||||
# NOTE: We do not generate for the -normal variant currently, that would just be
|
||||
# a stupid amount of compute and time for little benefit
|
||||
@@ -215,9 +220,7 @@ def render_for_screen(state: RenderState, flavor: Flavor, screen: str, ident: st
|
||||
|
||||
|
||||
def render_for_flavor(flavor: Flavor, state: RenderState):
|
||||
print(
|
||||
f"Starting render tasks for {flavor.identifier}"
|
||||
)
|
||||
print(f"Starting render tasks for {flavor.identifier}")
|
||||
for ident in INDEX:
|
||||
render_for_screen(state=state, flavor=flavor, screen="", ident=ident)
|
||||
render_for_screen(state=state, flavor=flavor, screen="-hdpi", ident=ident)
|