From 583a0c19ad2f67a54130a219eeeaccf53ea08ded Mon Sep 17 00:00:00 2001 From: Dylan Araps Date: Mon, 26 Jun 2017 12:09:35 +1000 Subject: [PATCH] General: Split wal into multiple files. --- pywal/__main__.py | 108 +++++++- pywal/export.py | 71 ++++++ pywal/gen_colors.py | 157 ++++++++++++ pywal/set_colors.py | 92 +++++++ pywal/settings.py | 33 +++ pywal/util.py | 54 ++++ pywal/wal.py | 584 -------------------------------------------- pywal/wallpaper.py | 84 +++++++ setup.py | 4 +- 9 files changed, 599 insertions(+), 588 deletions(-) create mode 100644 pywal/export.py create mode 100644 pywal/gen_colors.py create mode 100644 pywal/set_colors.py create mode 100644 pywal/settings.py create mode 100644 pywal/util.py delete mode 100755 pywal/wal.py create mode 100644 pywal/wallpaper.py diff --git a/pywal/__main__.py b/pywal/__main__.py index 4781f8f..7ede827 100755 --- a/pywal/__main__.py +++ b/pywal/__main__.py @@ -2,7 +2,111 @@ wal - Generate and change colorschemes on the fly. Created by Dylan Araps. """ -from pywal.wal import main +import argparse +import os +import shutil +import sys + +from pywal import settings as s +from pywal import export +from pywal import gen_colors +from pywal import set_colors +from pywal import wallpaper +from pywal import util -main() +__version__ = "0.1.6" + + +def get_args(): + """Get the script arguments.""" + description = "wal - Generate colorschemes on the fly" + arg = argparse.ArgumentParser(description=description) + + # Add the args. + arg.add_argument("-c", action="store_true", + help="Delete all cached colorschemes.") + + arg.add_argument("-i", metavar="\"/path/to/img.jpg\"", + help="Which image or directory to use.") + + arg.add_argument("-n", action="store_true", + help="Skip setting the wallpaper.") + + arg.add_argument("-o", metavar="\"script_name\"", + help="External script to run after \"wal\".") + + arg.add_argument("-q", action="store_true", + help="Quiet mode, don\"t print anything and \ + don't display notifications.") + + arg.add_argument("-r", action="store_true", + help="Reload current colorscheme.") + + arg.add_argument("-t", action="store_true", + help="Fix artifacts in VTE Terminals. \ + (Termite, xfce4-terminal)") + + arg.add_argument("-v", action="store_true", + help="Print \"wal\" version.") + + return arg.parse_args() + + +def process_args(args): + """Process args.""" + # If no args were passed. + if not len(sys.argv) > 1: + print("error: wal needs to be given arguments to run.\n" + " Refer to \"wal -h\" for more info.") + exit(1) + + # -q + if args.q: + sys.stdout = sys.stderr = open(os.devnull, "w") + s.Args.notify = False + + # -c + if args.c: + shutil.rmtree(s.CACHE_DIR / "schemes") + util.create_cache_dir() + + # -r + if args.r: + gen_colors.reload_colors(args.t) + + # -v + if args.v: + print(f"wal {__version__}") + exit(0) + + # -i + if args.i: + image = gen_colors.get_image(args.i) + s.ColorType.plain = gen_colors.get_colors(image) + + if not args.n: + wallpaper.set_wallpaper(image) + + # Set the colors. + set_colors.send_sequences(s.ColorType.plain, args.t) + export.export_colors(s.ColorType.plain) + + # -o + if args.o: + util.disown(args.o) + + +def main(): + """Main script function.""" + util.create_cache_dir() + args = get_args() + process_args(args) + + # This saves 10ms. + # pylint: disable=W0212 + # os._exit(0) + + +if __name__ == "__main__": + main() diff --git a/pywal/export.py b/pywal/export.py new file mode 100644 index 0000000..dfb774c --- /dev/null +++ b/pywal/export.py @@ -0,0 +1,71 @@ +""" +Export colors in various formats. +""" +import shutil +import subprocess + +from pywal import settings as s +from pywal import util + + +def save_colors(colors, export_file, message): + """Export colors to var format.""" + colors = "\n".join(colors) + util.save_file(f"{colors}\n", s.CACHE_DIR / export_file) + print(f"export: exported {message}.") + + +def export_rofi(colors): + """Append rofi colors to the x_colors list.""" + s.ColorType.xrdb.append(f"rofi.color-window: {colors[0]}, " + f"{colors[0]}, {colors[10]}") + s.ColorType.xrdb.append(f"rofi.color-normal: {colors[0]}, " + f"{colors[15]}, {colors[0]}, " + f"{colors[10]}, {colors[0]}") + s.ColorType.xrdb.append(f"rofi.color-active: {colors[0]}, " + f"{colors[15]}, {colors[0]}, " + f"{colors[10]}, {colors[0]}") + s.ColorType.xrdb.append(f"rofi.color-urgent: {colors[0]}, " + f"{colors[9]}, {colors[0]}, " + f"{colors[9]}, {colors[15]}") + + +def export_emacs(colors): + """Set emacs colors.""" + s.ColorType.xrdb.append(f"emacs*background: {colors[0]}") + s.ColorType.xrdb.append(f"emacs*foreground: {colors[15]}") + + +def reload_xrdb(export_file): + """Merge the colors into the X db so new terminals use them.""" + if shutil.which("xrdb"): + subprocess.call(["xrdb", "-merge", s.CACHE_DIR / export_file]) + + +def reload_i3(): + """Reload i3 colors.""" + if shutil.which("i3-msg"): + util.disown("i3-msg", "reload") + + +def export_colors(colors): + """Export colors in various formats.""" + save_colors(s.ColorType.plain, "colors", "plain hex colors") + save_colors(s.ColorType.shell, "colors.sh", "shell variables") + + # Web based colors. + s.ColorType.css.append("}") + save_colors(s.ColorType.css, "colors.css", "css variables") + save_colors(s.ColorType.scss, "colors.scss", "scss variables") + + # Text editor based colors. + save_colors(s.ColorType.putty, "colors-putty.reg", "putty theme") + + # X based colors. + export_rofi(colors) + export_emacs(colors) + save_colors(s.ColorType.xrdb, "xcolors", "xrdb colors") + + # i3 colors. + reload_xrdb("xcolors") + reload_i3() diff --git a/pywal/gen_colors.py b/pywal/gen_colors.py new file mode 100644 index 0000000..327d073 --- /dev/null +++ b/pywal/gen_colors.py @@ -0,0 +1,157 @@ +""" +Generate a colorscheme. +""" +import os +import pathlib +import random +import re +import shutil +import subprocess + +from pywal import settings as s +from pywal import set_colors +from pywal import util + + +CACHE_DIR = s.CACHE_DIR +COLOR_COUNT = s.COLOR_COUNT + + +def get_image(img): + """Validate image input.""" + # Check if the user has Imagemagick installed. + if not shutil.which("convert"): + print("error: imagemagick not found, exiting...\n" + "error: wal requires imagemagick to function.") + exit(1) + + image = pathlib.Path(img) + + if image.is_file(): + wal_img = image + + # Pick a random image from the directory. + elif image.is_dir(): + file_types = (".png", ".jpg", ".jpeg", ".jpe", ".gif") + + # Get the filename of the current wallpaper. + current_img = pathlib.Path(CACHE_DIR / "wal") + + if current_img.is_file(): + current_img = util.read_file(current_img) + current_img = os.path.basename(current_img[0]) + + # Get a list of images. + images = [img for img in os.listdir(image) + if img.endswith(file_types) and + img != current_img] + + wal_img = random.choice(images) + wal_img = pathlib.Path(image / wal_img) + + else: + print("error: No valid image file found.") + exit(1) + + print("image: Using image", wal_img) + return str(wal_img) + + +def imagemagick(color_count, img): + """Call Imagemagick to generate a scheme.""" + colors = subprocess.Popen(["convert", img, "+dither", "-colors", + str(color_count), "-unique-colors", "txt:-"], + stdout=subprocess.PIPE) + + return colors.stdout.readlines() + + +def gen_colors(img): + """Generate a color palette using imagemagick.""" + # Generate initial scheme. + raw_colors = imagemagick(COLOR_COUNT, img) + + # If imagemagick finds less than 16 colors, use a larger source number + # of colors. + index = 0 + while len(raw_colors) - 1 < COLOR_COUNT: + index += 1 + raw_colors = imagemagick(COLOR_COUNT + index, img) + + print("colors: Imagemagick couldn't generate a", COLOR_COUNT, + "color palette, trying a larger palette size", + COLOR_COUNT + index) + + # Remove the first element, which isn't a color. + del raw_colors[0] + + # Create a list of hex colors. + return [re.search("#.{6}", str(col)).group(0) for col in raw_colors] + + +def get_colors(img): + """Generate a colorscheme using imagemagick.""" + # Cache the wallpaper name. + util.save_file(img, CACHE_DIR / "wal") + + # Cache the sequences file. + cache_file = pathlib.Path(CACHE_DIR / "schemes" / img.replace("/", "_")) + + if cache_file.is_file(): + colors = util.read_file(cache_file) + print("colors: Found cached colorscheme.") + + else: + print("colors: Generating a colorscheme...") + util.notify("wal: Generating a colorscheme...") + + # Generate the colors. + colors = gen_colors(img) + colors = sort_colors(colors) + + # Cache the colorscheme. + util.save_file("\n".join(colors), cache_file) + + print("colors: Generated colorscheme") + util.notify("wal: Generation complete.") + + return colors + + +def sort_colors(colors): + """Sort the generated colors.""" + sorted_colors = [] + sorted_colors.append(colors[0]) + sorted_colors.append(colors[9]) + sorted_colors.append(colors[10]) + sorted_colors.append(colors[11]) + sorted_colors.append(colors[12]) + sorted_colors.append(colors[13]) + sorted_colors.append(colors[14]) + sorted_colors.append(colors[15]) + sorted_colors.append(set_colors.set_grey(colors)) + sorted_colors.append(colors[9]) + sorted_colors.append(colors[10]) + sorted_colors.append(colors[11]) + sorted_colors.append(colors[12]) + sorted_colors.append(colors[13]) + sorted_colors.append(colors[14]) + sorted_colors.append(colors[15]) + return sorted_colors + + +def reload_colors(vte): + """Reload colors.""" + sequence_file = pathlib.Path(CACHE_DIR / "sequences") + + if sequence_file.is_file(): + sequences = "".join(util.read_file(sequence_file)) + + # If vte mode was used, remove the problem sequence. + if vte: + sequences = re.sub(r"\]708;\#.{6}", "", sequences) + + # Make the terminal interpret escape sequences. + print(util.fix_escape(sequences), end="") + + exit(0) diff --git a/pywal/set_colors.py b/pywal/set_colors.py new file mode 100644 index 0000000..4b3c74f --- /dev/null +++ b/pywal/set_colors.py @@ -0,0 +1,92 @@ +""" +Send sequences to all open terminals. +""" +import os + +from pywal import settings as s +from pywal import util + + +def set_special(index, color): + """Build the escape sequence for special colors.""" + s.ColorType.sequences.append(f"\\033]{index};{color}\\007") + + if index == 10: + s.ColorType.xrdb.append(f"URxvt*foreground: {color}") + s.ColorType.xrdb.append(f"XTerm*foreground: {color}") + + elif index == 11: + s.ColorType.xrdb.append(f"URxvt*background: {color}") + s.ColorType.xrdb.append(f"XTerm*background: {color}") + + elif index == 12: + s.ColorType.xrdb.append(f"URxvt*cursorColor: {color}") + s.ColorType.xrdb.append(f"XTerm*cursorColor: {color}") + + elif index == 66: + s.ColorType.xrdb.append(f"*.color{index}: {color}") + s.ColorType.xrdb.append(f"*color{index}: {color}") + s.ColorType.sequences.append(f"\\033]4;{index};{color}\\007") + + +def set_color(index, color): + """Build the escape sequence we need for each color.""" + s.ColorType.xrdb.append(f"*.color{index}: {color}") + s.ColorType.xrdb.append(f"*color{index}: {color}") + s.ColorType.sequences.append(f"\\033]4;{index};{color}\\007") + s.ColorType.shell.append(f"color{index}='{color}'") + s.ColorType.css.append(f"\t--color{index}: {color};") + s.ColorType.scss.append(f"$color{index}: {color};") + + rgb = util.hex_to_rgb(color) + s.ColorType.putty.append(f"\"Colour{index}\"=\"{rgb}\"") + + +def set_grey(colors): + """Set a grey color based on brightness of color0.""" + return { + 0: "#666666", + 1: "#666666", + 2: "#757575", + 3: "#999999", + 4: "#999999", + 5: "#8a8a8a", + 6: "#a1a1a1", + 7: "#a1a1a1", + 8: "#a1a1a1", + 9: "#a1a1a1", + }.get(int(colors[0][1]), colors[7]) + + +def send_sequences(colors, vte): + """Send colors to all open terminals.""" + set_special(10, colors[15]) + set_special(11, colors[0]) + set_special(12, colors[15]) + set_special(13, colors[15]) + set_special(14, colors[0]) + + # This escape sequence doesn"t work in VTE terminals. + if not vte: + set_special(708, colors[0]) + + # Create the sequences. + # pylint: disable=W0106 + [set_color(num, color) for num, color in enumerate(colors)] + + # Set a blank color that isn"t affected by bold highlighting. + set_special(66, colors[0]) + + # Make the terminal interpret escape sequences. + sequences = util.fix_escape("".join(s.ColorType.sequences)) + + # Get a list of terminals. + terminals = [f"/dev/pts/{term}" for term in os.listdir("/dev/pts/") + if len(term) < 4] + terminals.append(s.CACHE_DIR / "sequences") + + # Send the sequences to all open terminals. + # pylint: disable=W0106 + [util.save_file(sequences, term) for term in terminals] + + print("colors: Set terminal colors") diff --git a/pywal/settings.py b/pywal/settings.py new file mode 100644 index 0000000..387178b --- /dev/null +++ b/pywal/settings.py @@ -0,0 +1,33 @@ +""" +Global variables and classes. +""" +import pathlib + + +__version__ = "0.1.6" + + +# Internal variables. +COLOR_COUNT = 16 +CACHE_DIR = pathlib.Path.home() / ".cache/wal/" + + +# pylint: disable=too-few-public-methods +class ColorType(object): + """Store colors in various formats.""" + plain = [] + xrdb = [] + sequences = [] + shell = [] + scss = [] + css = [":root {"] + putty = [ + "Windows Registry Editor Version 5.00", + "[HKEY_CURRENT_USER\\Software\\SimonTatham\\PuTTY\\Sessions\\Wal]", + ] + + +# pylint: disable=too-few-public-methods +class Args(object): + """Store args.""" + notify = True diff --git a/pywal/util.py b/pywal/util.py new file mode 100644 index 0000000..061c94e --- /dev/null +++ b/pywal/util.py @@ -0,0 +1,54 @@ +""" +Misc helper functions. +""" +import os +import pathlib +import subprocess +import shutil + +from pywal import settings as s + + +def read_file(input_file): + """Read colors from a file.""" + return open(input_file).read().splitlines() + + +def save_file(colors, export_file): + """Write the colors to the file.""" + with open(export_file, "w") as file: + file.write(colors) + + +def create_cache_dir(): + """Alias to create the cache dir.""" + pathlib.Path(s.CACHE_DIR / "schemes").mkdir(parents=True, exist_ok=True) + + +def hex_to_rgb(color): + """Convert a hex color to rgb.""" + red, green, blue = list(bytes.fromhex(color.strip("#"))) + return f"{red},{green},{blue}" + + +def fix_escape(string): + """Decode a string.""" + return bytes(string, "utf-8").decode("unicode_escape") + + +def notify(msg): + """Send arguements to notify-send.""" + if shutil.which("notify-send") and s.Args.notify: + subprocess.Popen(["notify-send", msg], + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + preexec_fn=os.setpgrp) + + +def disown(*cmd): + """Call a system command in the background, + disown it and hide it's output.""" + subprocess.Popen(["nohup"] + list(cmd), + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + preexec_fn=os.setpgrp) diff --git a/pywal/wal.py b/pywal/wal.py deleted file mode 100755 index fb5861b..0000000 --- a/pywal/wal.py +++ /dev/null @@ -1,584 +0,0 @@ -""" -wal - Generate and change colorschemes on the fly. -Created by Dylan Araps. -""" -import argparse -import os -import pathlib -import random -import re -import shutil -import subprocess -import sys - - -__version__ = "0.1.6" - - -# Internal variables. -COLOR_COUNT = 16 -CACHE_DIR = pathlib.Path.home() / ".cache/wal/" - - -# pylint: disable=too-few-public-methods -class ColorType(object): - """Store colors in various formats.""" - plain = [] - xrdb = [] - sequences = [] - shell = [] - scss = [] - css = [":root {"] - putty = [ - "Windows Registry Editor Version 5.00", - "[HKEY_CURRENT_USER\\Software\\SimonTatham\\PuTTY\\Sessions\\Wal]", - ] - - -# pylint: disable=too-few-public-methods -class Args(object): - """Store args.""" - notify = True - - -# ARGS {{{ - - -def get_args(): - """Get the script arguments.""" - description = "wal - Generate colorschemes on the fly" - arg = argparse.ArgumentParser(description=description) - - # Add the args. - arg.add_argument("-c", action="store_true", - help="Delete all cached colorschemes.") - - arg.add_argument("-i", metavar="\"/path/to/img.jpg\"", - help="Which image or directory to use.") - - arg.add_argument("-n", action="store_true", - help="Skip setting the wallpaper.") - - arg.add_argument("-o", metavar="\"script_name\"", - help="External script to run after \"wal\".") - - arg.add_argument("-q", action="store_true", - help="Quiet mode, don\"t print anything and \ - don't display notifications.") - - arg.add_argument("-r", action="store_true", - help="Reload current colorscheme.") - - arg.add_argument("-t", action="store_true", - help="Fix artifacts in VTE Terminals. \ - (Termite, xfce4-terminal)") - - arg.add_argument("-v", action="store_true", - help="Print \"wal\" version.") - - return arg.parse_args() - - -def process_args(args): - """Process args.""" - # If no args were passed. - if not len(sys.argv) > 1: - print("error: wal needs to be given arguments to run.\n" - " Refer to \"wal -h\" for more info.") - exit(1) - - # -q - if args.q: - sys.stdout = sys.stderr = open(os.devnull, "w") - Args.notify = False - - # -c - if args.c: - shutil.rmtree(CACHE_DIR / "schemes") - create_cache_dir() - - # -r - if args.r: - reload_colors(args.t) - - # -v - if args.v: - print(f"wal {__version__}") - exit(0) - - # -i - if args.i: - image = get_image(args.i) - ColorType.plain = get_colors(image) - - if not args.n: - set_wallpaper(image) - - # Set the colors. - send_sequences(ColorType.plain, args.t) - export_colors(ColorType.plain) - - # -o - if args.o: - disown(args.o) - - -# }}} - - -# COLORSCHEME GENERATION {{{ - - -def get_image(img): - """Validate image input.""" - # Check if the user has Imagemagick installed. - if not shutil.which("convert"): - print("error: imagemagick not found, exiting...\n" - "error: wal requires imagemagick to function.") - exit(1) - - image = pathlib.Path(img) - - if image.is_file(): - wal_img = image - - # Pick a random image from the directory. - elif image.is_dir(): - file_types = (".png", ".jpg", ".jpeg", ".jpe", ".gif") - - # Get the filename of the current wallpaper. - current_img = pathlib.Path(CACHE_DIR / "wal") - - if current_img.is_file(): - current_img = read_file(current_img) - current_img = os.path.basename(current_img[0]) - - # Get a list of images. - images = [img for img in os.listdir(image) - if img.endswith(file_types) and - img != current_img] - - wal_img = random.choice(images) - wal_img = pathlib.Path(image / wal_img) - - else: - print("error: No valid image file found.") - exit(1) - - print("image: Using image", wal_img) - return str(wal_img) - - -def imagemagick(color_count, img): - """Call Imagemagick to generate a scheme.""" - colors = subprocess.Popen(["convert", img, "+dither", "-colors", - str(color_count), "-unique-colors", "txt:-"], - stdout=subprocess.PIPE) - - return colors.stdout.readlines() - - -def gen_colors(img): - """Generate a color palette using imagemagick.""" - # Generate initial scheme. - raw_colors = imagemagick(COLOR_COUNT, img) - - # If imagemagick finds less than 16 colors, use a larger source number - # of colors. - index = 0 - while len(raw_colors) - 1 < COLOR_COUNT: - index += 1 - raw_colors = imagemagick(COLOR_COUNT + index, img) - - print("colors: Imagemagick couldn't generate a", COLOR_COUNT, - "color palette, trying a larger palette size", - COLOR_COUNT + index) - - # Remove the first element, which isn't a color. - del raw_colors[0] - - # Create a list of hex colors. - return [re.search("#.{6}", str(col)).group(0) for col in raw_colors] - - -def get_colors(img): - """Generate a colorscheme using imagemagick.""" - # Cache the wallpaper name. - save_file(img, CACHE_DIR / "wal") - - # Cache the sequences file. - cache_file = pathlib.Path(CACHE_DIR / "schemes" / img.replace("/", "_")) - - if cache_file.is_file(): - colors = read_file(cache_file) - print("colors: Found cached colorscheme.") - - else: - print("colors: Generating a colorscheme...") - notify("wal: Generating a colorscheme...") - - # Generate the colors. - colors = gen_colors(img) - colors = sort_colors(colors) - - # Cache the colorscheme. - save_file("\n".join(colors), cache_file) - - print("colors: Generated colorscheme") - notify("wal: Generation complete.") - - return colors - - -def sort_colors(colors): - """Sort the generated colors.""" - sorted_colors = [] - sorted_colors.append(colors[0]) - sorted_colors.append(colors[9]) - sorted_colors.append(colors[10]) - sorted_colors.append(colors[11]) - sorted_colors.append(colors[12]) - sorted_colors.append(colors[13]) - sorted_colors.append(colors[14]) - sorted_colors.append(colors[15]) - sorted_colors.append(set_grey(colors)) - sorted_colors.append(colors[9]) - sorted_colors.append(colors[10]) - sorted_colors.append(colors[11]) - sorted_colors.append(colors[12]) - sorted_colors.append(colors[13]) - sorted_colors.append(colors[14]) - sorted_colors.append(colors[15]) - return sorted_colors - - -# }}} - - -# SEND SEQUENCES {{{ - - -def set_special(index, color): - """Build the escape sequence for special colors.""" - ColorType.sequences.append(f"\\033]{index};{color}\\007") - - if index == 10: - ColorType.xrdb.append(f"URxvt*foreground: {color}") - ColorType.xrdb.append(f"XTerm*foreground: {color}") - - elif index == 11: - ColorType.xrdb.append(f"URxvt*background: {color}") - ColorType.xrdb.append(f"XTerm*background: {color}") - - elif index == 12: - ColorType.xrdb.append(f"URxvt*cursorColor: {color}") - ColorType.xrdb.append(f"XTerm*cursorColor: {color}") - - elif index == 66: - ColorType.xrdb.append(f"*.color{index}: {color}") - ColorType.xrdb.append(f"*color{index}: {color}") - ColorType.sequences.append(f"\\033]4;{index};{color}\\007") - - -def set_color(index, color): - """Build the escape sequence we need for each color.""" - ColorType.xrdb.append(f"*.color{index}: {color}") - ColorType.xrdb.append(f"*color{index}: {color}") - ColorType.sequences.append(f"\\033]4;{index};{color}\\007") - ColorType.shell.append(f"color{index}='{color}'") - ColorType.css.append(f"\t--color{index}: {color};") - ColorType.scss.append(f"$color{index}: {color};") - - rgb = hex_to_rgb(color) - ColorType.putty.append(f"\"Colour{index}\"=\"{rgb}\"") - - -def set_grey(colors): - """Set a grey color based on brightness of color0.""" - return { - 0: "#666666", - 1: "#666666", - 2: "#757575", - 3: "#999999", - 4: "#999999", - 5: "#8a8a8a", - 6: "#a1a1a1", - 7: "#a1a1a1", - 8: "#a1a1a1", - 9: "#a1a1a1", - }.get(int(colors[0][1]), colors[7]) - - -def send_sequences(colors, vte): - """Send colors to all open terminals.""" - set_special(10, colors[15]) - set_special(11, colors[0]) - set_special(12, colors[15]) - set_special(13, colors[15]) - set_special(14, colors[0]) - - # This escape sequence doesn"t work in VTE terminals. - if not vte: - set_special(708, colors[0]) - - # Create the sequences. - # pylint: disable=W0106 - [set_color(num, color) for num, color in enumerate(colors)] - - # Set a blank color that isn"t affected by bold highlighting. - set_special(66, colors[0]) - - # Make the terminal interpret escape sequences. - sequences = fix_escape("".join(ColorType.sequences)) - - # Get a list of terminals. - terminals = [f"/dev/pts/{term}" for term in os.listdir("/dev/pts/") - if len(term) < 4] - terminals.append(CACHE_DIR / "sequences") - - # Send the sequences to all open terminals. - # pylint: disable=W0106 - [save_file(sequences, term) for term in terminals] - - print("colors: Set terminal colors") - - -# }}} - - -# WALLPAPER SETTING {{{ - - -def get_desktop_env(): - """Identify the current running desktop environment.""" - desktop = os.getenv("XDG_CURRENT_DESKTOP") - if desktop: - return desktop - - desktop = os.getenv("DESKTOP_SESSION") - if desktop: - return desktop - - desktop = os.getenv("GNOME_DESKTOP_SESSION_ID") - if desktop: - return "GNOME" - - desktop = os.getenv("MATE_DESKTOP_SESSION_ID") - if desktop: - return "MATE" - - -def xfconf(path, img): - """Call xfconf to set the wallpaper on XFCE.""" - disown("xfconf-query", "--channel", "xfce4-desktop", - "--property", path, "--set", img) - - -def set_desktop_wallpaper(desktop, img): - """Set the wallpaper for the desktop environment.""" - desktop = str(desktop).lower() - - if "xfce" in desktop or "xubuntu" in desktop: - # XFCE requires two commands since they differ between versions. - xfconf("/backdrop/screen0/monitor0/image-path", img) - xfconf("/backdrop/screen0/monitor0/workspace0/last-image", img) - - elif "muffin" in desktop or "cinnamon" in desktop: - subprocess.Popen(["gsettings", "set", - "org.cinnamon.desktop.background", - "picture-uri", "file:///" + img]) - - elif "gnome" in desktop: - subprocess.Popen(["gsettings", "set", - "org.gnome.desktop.background", - "picture-uri", "file:///" + img]) - - elif "mate" in desktop: - subprocess.Popen(["gsettings", "set", "org.mate.background", - "picture-filename", img]) - - -def set_wallpaper(img): - """Set the wallpaper.""" - desktop = get_desktop_env() - - if desktop: - set_desktop_wallpaper(desktop, img) - - else: - if shutil.which("feh"): - subprocess.Popen(["feh", "--bg-fill", img]) - - elif shutil.which("nitrogen"): - subprocess.Popen(["nitrogen", "--set-zoom-fill", img]) - - elif shutil.which("bgs"): - subprocess.Popen(["bgs", img]) - - elif shutil.which("hsetroot"): - subprocess.Popen(["hsetroot", "-fill", img]) - - elif shutil.which("habak"): - subprocess.Popen(["habak", "-mS", img]) - - else: - print("error: No wallpaper setter found.") - return - - print("wallpaper: Set the new wallpaper") - return 0 - - -# }}} - - -# EXPORT COLORS {{{ - - -def save_colors(colors, export_file, message): - """Export colors to var format.""" - colors = "\n".join(colors) - save_file(f"{colors}\n", CACHE_DIR / export_file) - print(f"export: exported {message}.") - - -def export_rofi(colors): - """Append rofi colors to the x_colors list.""" - ColorType.xrdb.append(f"rofi.color-window: {colors[0]}, " - f"{colors[0]}, {colors[10]}") - ColorType.xrdb.append(f"rofi.color-normal: {colors[0]}, " - f"{colors[15]}, {colors[0]}, " - f"{colors[10]}, {colors[0]}") - ColorType.xrdb.append(f"rofi.color-active: {colors[0]}, " - f"{colors[15]}, {colors[0]}, " - f"{colors[10]}, {colors[0]}") - ColorType.xrdb.append(f"rofi.color-urgent: {colors[0]}, " - f"{colors[9]}, {colors[0]}, " - f"{colors[9]}, {colors[15]}") - - -def export_emacs(colors): - """Set emacs colors.""" - ColorType.xrdb.append(f"emacs*background: {colors[0]}") - ColorType.xrdb.append(f"emacs*foreground: {colors[15]}") - - -def reload_xrdb(export_file): - """Merge the colors into the X db so new terminals use them.""" - if shutil.which("xrdb"): - subprocess.call(["xrdb", "-merge", CACHE_DIR / export_file]) - - -def reload_i3(): - """Reload i3 colors.""" - if shutil.which("i3-msg"): - disown("i3-msg", "reload") - - -def export_colors(colors): - """Export colors in various formats.""" - save_colors(ColorType.plain, "colors", "plain hex colors") - save_colors(ColorType.shell, "colors.sh", "shell variables") - - # Web based colors. - ColorType.css.append("}") - save_colors(ColorType.css, "colors.css", "css variables") - save_colors(ColorType.scss, "colors.scss", "scss variables") - - # Text editor based colors. - save_colors(ColorType.putty, "colors-putty.reg", "putty theme") - - # X based colors. - export_rofi(colors) - export_emacs(colors) - save_colors(ColorType.xrdb, "xcolors", "xrdb colors") - - # i3 colors. - reload_xrdb("xcolors") - reload_i3() - - -# }}} - - -# OTHER FUNCTIONS {{{ - - -def reload_colors(vte): - """Reload colors.""" - sequence_file = pathlib.Path(CACHE_DIR / "sequences") - - if sequence_file.is_file(): - sequences = "".join(read_file(sequence_file)) - - # If vte mode was used, remove the problem sequence. - if vte: - sequences = re.sub(r"\]708;\#.{6}", "", sequences) - - # Make the terminal interpret escape sequences. - print(fix_escape(sequences), end="") - - exit(0) - - -def read_file(input_file): - """Read colors from a file.""" - return open(input_file).read().splitlines() - - -def save_file(colors, export_file): - """Write the colors to the file.""" - with open(export_file, "w") as file: - file.write(colors) - - -def create_cache_dir(): - """Alias to create the cache dir.""" - pathlib.Path(CACHE_DIR / "schemes").mkdir(parents=True, exist_ok=True) - - -def hex_to_rgb(color): - """Convert a hex color to rgb.""" - red, green, blue = list(bytes.fromhex(color.strip("#"))) - return f"{red},{green},{blue}" - - -def fix_escape(string): - """Decode a string.""" - return bytes(string, "utf-8").decode("unicode_escape") - - -def notify(msg): - """Send arguements to notify-send.""" - if shutil.which("notify-send") and Args.notify: - subprocess.Popen(["notify-send", msg], - stdout=subprocess.DEVNULL, - stderr=subprocess.DEVNULL, - preexec_fn=os.setpgrp) - - -def disown(*cmd): - """Call a system command in the background, - disown it and hide it's output.""" - subprocess.Popen(["nohup"] + list(cmd), - stdout=subprocess.DEVNULL, - stderr=subprocess.DEVNULL, - preexec_fn=os.setpgrp) - - -# }}} - - -def main(): - """Main script function.""" - create_cache_dir() - args = get_args() - process_args(args) - - # This saves 10ms. - # pylint: disable=W0212 - # os._exit(0) - - -if __name__ == "__main__": - main() diff --git a/pywal/wallpaper.py b/pywal/wallpaper.py new file mode 100644 index 0000000..39c44bf --- /dev/null +++ b/pywal/wallpaper.py @@ -0,0 +1,84 @@ +"""Set the wallpaper.""" +import os +import shutil +import subprocess + + +def get_desktop_env(): + """Identify the current running desktop environment.""" + desktop = os.getenv("XDG_CURRENT_DESKTOP") + if desktop: + return desktop + + desktop = os.getenv("DESKTOP_SESSION") + if desktop: + return desktop + + desktop = os.getenv("GNOME_DESKTOP_SESSION_ID") + if desktop: + return "GNOME" + + desktop = os.getenv("MATE_DESKTOP_SESSION_ID") + if desktop: + return "MATE" + + +def xfconf(path, img): + """Call xfconf to set the wallpaper on XFCE.""" + disown("xfconf-query", "--channel", "xfce4-desktop", + "--property", path, "--set", img) + + +def set_desktop_wallpaper(desktop, img): + """Set the wallpaper for the desktop environment.""" + desktop = str(desktop).lower() + + if "xfce" in desktop or "xubuntu" in desktop: + # XFCE requires two commands since they differ between versions. + xfconf("/backdrop/screen0/monitor0/image-path", img) + xfconf("/backdrop/screen0/monitor0/workspace0/last-image", img) + + elif "muffin" in desktop or "cinnamon" in desktop: + subprocess.Popen(["gsettings", "set", + "org.cinnamon.desktop.background", + "picture-uri", "file:///" + img]) + + elif "gnome" in desktop: + subprocess.Popen(["gsettings", "set", + "org.gnome.desktop.background", + "picture-uri", "file:///" + img]) + + elif "mate" in desktop: + subprocess.Popen(["gsettings", "set", "org.mate.background", + "picture-filename", img]) + + +def set_wallpaper(img): + """Set the wallpaper.""" + desktop = get_desktop_env() + + if desktop: + set_desktop_wallpaper(desktop, img) + + else: + if shutil.which("feh"): + subprocess.Popen(["feh", "--bg-fill", img]) + + elif shutil.which("nitrogen"): + subprocess.Popen(["nitrogen", "--set-zoom-fill", img]) + + elif shutil.which("bgs"): + subprocess.Popen(["bgs", img]) + + elif shutil.which("hsetroot"): + subprocess.Popen(["hsetroot", "-fill", img]) + + elif shutil.which("habak"): + subprocess.Popen(["habak", "-mS", img]) + + else: + print("error: No wallpaper setter found.") + return + + print("wallpaper: Set the new wallpaper") + return 0 diff --git a/setup.py b/setup.py index 660cc64..c0f86ed 100644 --- a/setup.py +++ b/setup.py @@ -1,6 +1,6 @@ """wal - setup.py""" from setuptools import setup -import pywal +import pywal.__main__ as pywal DESC = ( @@ -11,7 +11,7 @@ DESC = ( DESC = "".join(DESC) -VERSION = pywal.wal.__version__ +VERSION = pywal.__version__ DOWNLOAD_URL = f"https://github.com/dylanaraps/pywal/archive/{VERSION}.tar.gz"