upload
This commit is contained in:
119
bin/gtkcolors.py
Executable file
119
bin/gtkcolors.py
Executable file
@@ -0,0 +1,119 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
"""
|
||||
Based on labwc-gtktheme.py:
|
||||
Create labwc theme based on the current Gtk theme
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
Copyright (C) @Misko_2083 2019
|
||||
Copyright (C) Johan Malm 2019-2022
|
||||
"""
|
||||
|
||||
import os
|
||||
import errno
|
||||
from tokenize import tokenize, NUMBER, NAME, OP
|
||||
from io import BytesIO
|
||||
import gi
|
||||
gi.require_version("Gtk", "3.0")
|
||||
from gi.repository import Gtk
|
||||
|
||||
def parse(tokens):
|
||||
"""
|
||||
Parse css color expression token list and return red/green/blue values
|
||||
Valid name-tokens include 'rgb' and 'rgba', whereas 'alpha', 'shade' and
|
||||
'mix' are ignored. @other-color references are still to be implemented.
|
||||
"""
|
||||
nr_colors_to_parse = 0
|
||||
in_label = False
|
||||
color = []
|
||||
for toknum, tokval, _, _, _ in tokens:
|
||||
if '@' in tokval:
|
||||
in_label = True
|
||||
continue
|
||||
if toknum == NAME and in_label:
|
||||
color.clear()
|
||||
color.append(f"@{tokval}")
|
||||
return color
|
||||
if nr_colors_to_parse > 0:
|
||||
if toknum == OP and tokval in ')':
|
||||
print("warn: still parsing numbers; did not expect ')'")
|
||||
if toknum == NUMBER:
|
||||
color.append(tokval)
|
||||
nr_colors_to_parse -= 1
|
||||
continue
|
||||
if toknum == NAME and tokval in 'rgb':
|
||||
nr_colors_to_parse = 3
|
||||
elif toknum == NAME and tokval in 'rgba':
|
||||
nr_colors_to_parse = 4
|
||||
return color
|
||||
|
||||
def color_hex(color):
|
||||
""" return rrggbb color hex from list [r, g, b,...] """
|
||||
if not color:
|
||||
return "None"
|
||||
elif len(color) < 3:
|
||||
return f"{color[0]}"
|
||||
return '{:02x}{:02x}{:02x}'.format(*(int(x) for x in color[:3]))
|
||||
|
||||
def hex_from_expr(line):
|
||||
""" parse color expression to return hex style rrggbb """
|
||||
tokens = tokenize(BytesIO(line.encode('utf-8')).readline)
|
||||
color = parse(tokens)
|
||||
return color_hex(color)
|
||||
|
||||
def parse_section(lines, name):
|
||||
theme = {}
|
||||
inside = False
|
||||
for line in lines:
|
||||
if f"{name} {{" in line:
|
||||
inside = True
|
||||
continue
|
||||
if inside:
|
||||
if "}" in line or "{" in line:
|
||||
inside = False
|
||||
break
|
||||
if 'color' not in line:
|
||||
continue
|
||||
key, value = line.strip().split(":", maxsplit=1)
|
||||
theme[f'{name}.{key.replace(" ", "")}'] = hex_from_expr(value)
|
||||
return theme
|
||||
|
||||
def resolve_labels(theme):
|
||||
for key, label in theme.items():
|
||||
if '@' in label:
|
||||
for tmp, value in theme.items():
|
||||
if tmp == label[1:]:
|
||||
theme[key] = value
|
||||
return resolve_labels(theme)
|
||||
return theme
|
||||
|
||||
def main():
|
||||
""" main """
|
||||
|
||||
gset = Gtk.Settings.get_default()
|
||||
themename = gset.get_property("gtk-theme-name")
|
||||
css = Gtk.CssProvider.get_named(themename).to_string()
|
||||
|
||||
lines = css.split("\n")
|
||||
theme = {}
|
||||
|
||||
# Parse @define-color lines using syntax "@define-color <key> <value>"
|
||||
for line in lines:
|
||||
if "@define-color" not in line:
|
||||
continue
|
||||
x = line.split(" ", maxsplit=2)
|
||||
theme[x[1]] = hex_from_expr(x[2])
|
||||
|
||||
# Add the color definitions in the headerbar{} and menu{} sections
|
||||
theme |= parse_section(lines, "headerbar")
|
||||
theme |= parse_section(lines, "menu")
|
||||
|
||||
theme = resolve_labels(theme)
|
||||
|
||||
for key, value in theme.items():
|
||||
print(f"{key}: {value}")
|
||||
return
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user