Merge pull request #8 from dylanaraps/split

General: Split wal into multiple files.
This commit is contained in:
Dylan Araps 2017-06-27 01:04:31 +10:00 committed by GitHub
commit 5c7c84601b
12 changed files with 582 additions and 588 deletions

View File

@ -7,4 +7,4 @@ install:
script: script:
- flake8 pywal setup.py - flake8 pywal setup.py
- pylint pywal setup.py - pylint --ignore-imports=yes pywal setup.py

View File

@ -2,3 +2,4 @@
wal - Generate and change colorschemes on the fly. wal - Generate and change colorschemes on the fly.
Created by Dylan Araps. Created by Dylan Araps.
""" """
from pywal.settings import __version__ # noqa: F401

View File

@ -2,7 +2,110 @@
wal - Generate and change colorschemes on the fly. wal - Generate and change colorschemes on the fly.
Created by Dylan Araps. Created by Dylan Araps.
""" """
from pywal.wal import main import argparse
import os
import shutil
import sys
from pywal.settings import CACHE_DIR, __version__
from pywal import export_colors
from pywal import gen_colors
from pywal import set_colors
from pywal import wallpaper
from pywal import util
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")
# -c
if args.c:
shutil.rmtree(CACHE_DIR / "schemes")
util.create_dir(CACHE_DIR / "schemes")
# -r
if args.r:
set_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)
# Create a list of hex colors.
colors_plain = gen_colors.get_colors(image, args.q)
colors_plain[8] = set_colors.set_grey(colors_plain)
if not args.n:
wallpaper.set_wallpaper(image)
# Set the colors.
set_colors.send_sequences(colors_plain, args.t)
export_colors.export_colors(colors_plain)
# -o
if args.o:
util.disown(args.o)
def main():
"""Main script function."""
util.create_dir(CACHE_DIR / "schemes")
args = get_args()
process_args(args)
# This saves 10ms.
# pylint: disable=W0212
# os._exit(0)
if __name__ == "__main__":
main() main()

56
pywal/export_colors.py Executable file
View File

@ -0,0 +1,56 @@
"""
Export colors in various formats.
"""
import shutil
import subprocess
from pywal.settings import CACHE_DIR
from pywal import util
from pywal import format_color
def save_colors(colors, export_file, message):
"""Export colors to var format."""
colors = "".join(colors)
util.save_file(colors, CACHE_DIR / export_file)
print(f"export: exported {message}.")
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"):
util.disown("i3-msg", "reload")
def export_colors(colors):
"""Export colors in various formats."""
plain_colors = format_color.plain(colors)
save_colors(plain_colors, "colors", "plain hex colors")
# Shell based colors.
shell_colors = format_color.shell(colors)
save_colors(shell_colors, "colors.sh", "shell variables")
# Web based colors.
css_colors = format_color.css(colors)
save_colors(css_colors, "colors.css", "css variables")
scss_colors = format_color.scss(colors)
save_colors(scss_colors, "colors.scss", "scss variables")
# Text editor based colors.
putty_colors = format_color.putty(colors)
save_colors(putty_colors, "colors-putty.reg", "putty theme")
# X based colors.
xrdb_colors = format_color.xrdb(colors)
save_colors(xrdb_colors, "xcolors", "xrdb colors")
# i3 colors.
reload_xrdb("xcolors")
reload_i3()

78
pywal/format_color.py Executable file
View File

@ -0,0 +1,78 @@
"""
Convert colors to various formats.
"""
from pywal import util
def plain(colors):
"""Convert colors to plain hex."""
return [f"{color}\n" for color in colors]
def shell(colors):
"""Convert colors to shell variables."""
return [f"color{index}='{color}'\n"
for index, color in enumerate(colors)]
def css(colors):
"""Convert colors to css variables."""
css_colors = [":root {\n"]
css_colors.extend([f"\t--color{index}: {color};\n"
for index, color in enumerate(colors)])
css_colors.append("}\n")
return css_colors
def scss(colors):
"""Convert colors to scss variables."""
return [f"$color{index}: {color};\n"
for index, color in enumerate(colors)]
def putty(colors):
"""Convert colors to putty theme."""
rgb = util.hex_to_rgb
putty_colors = [
"Windows Registry Editor Version 5.00\n\n",
"[HKEY_CURRENT_USER\\Software\\SimonTatham\\PuTTY\\Sessions\\Wal]\n",
]
putty_colors.extend([f"\"colour{index}\"=\"{rgb(color)}\"\n"
for index, color in enumerate(colors)])
return putty_colors
def xrdb(colors):
"""Convert colors to xrdb format."""
x_colors = []
x_colors.append(f"URxvt*foreground: {colors[15]}\n")
x_colors.append(f"XTerm*foreground: {colors[15]}\n")
x_colors.append(f"URxvt*background: {colors[0]}\n")
x_colors.append(f"XTerm*background: {colors[0]}\n")
x_colors.append(f"URxvt*cursorColor: {colors[15]}\n")
x_colors.append(f"XTerm*cursorColor: {colors[15]}\n")
# Colors 0-15.
x_colors.extend([f"*.color{index}: {color}\n*color{index}: {color}\n"
for index, color in enumerate(colors)])
x_colors.append(f"*.color66: {colors[0]}\n*color66: {colors[0]}\n")
# Rofi colors.
x_colors.append(f"rofi.color-window: {colors[0]}, "
f"{colors[0]}, {colors[10]}\n")
x_colors.append(f"rofi.color-normal: {colors[0]}, "
f"{colors[15]}, {colors[0]}, "
f"{colors[10]}, {colors[0]}\n")
x_colors.append(f"rofi.color-active: {colors[0]}, "
f"{colors[15]}, {colors[0]}, "
f"{colors[10]}, {colors[0]}\n")
x_colors.append(f"rofi.color-urgent: {colors[0]}, "
f"{colors[9]}, {colors[0]}, "
f"{colors[9]}, {colors[15]}\n")
# Emacs colors.
x_colors.append(f"emacs*background: {colors[0]}\n")
x_colors.append(f"emacs*foreground: {colors[15]}\n")
return x_colors

120
pywal/gen_colors.py Executable file
View File

@ -0,0 +1,120 @@
"""
Generate a colorscheme.
"""
import os
import pathlib
import random
import re
import shutil
import subprocess
from pywal.settings import CACHE_DIR, COLOR_COUNT
from pywal import util
def random_img(img_dir):
"""Pick a random image file from a directory."""
current_wall = pathlib.Path(CACHE_DIR / "wal")
if current_wall.is_file():
current_wall = util.read_file(current_wall)
current_wall = os.path.basename(current_wall[0])
# Add all images to a list excluding the current wallpaper.
file_types = (".png", ".jpg", ".jpeg", ".jpe", ".gif")
images = [img for img in os.listdir(img_dir)
if img.endswith(file_types) and img != current_wall]
return pathlib.Path(img_dir / random.choice(images))
def get_image(img):
"""Validate image input."""
image = pathlib.Path(img)
if image.is_file():
wal_img = image
elif image.is_dir():
wal_img = random_img(image)
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."""
# 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)
# 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, quiet):
"""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...")
if not quiet:
util.disown("notify-send", "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")
if not quiet:
util.disown("notify-send", "wal: Generation complete.")
return colors
def sort_colors(colors):
"""Sort the generated colors."""
return colors[:1] + colors[9:] + colors[8:]

80
pywal/set_colors.py Executable file
View File

@ -0,0 +1,80 @@
"""
Send sequences to all open terminals.
"""
import os
import pathlib
import re
from pywal.settings import CACHE_DIR
from pywal import util
def set_special(index, color):
"""Build the escape sequence for special colors."""
return f"\033]{index};{color}\007"
def set_color(index, color):
"""Build the escape sequence we need for each color."""
return f"\033]4;{index};{color}\007"
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."""
sequences = [set_color(num, color) for num, color in enumerate(colors)]
sequences.append(set_special(10, colors[15]))
sequences.append(set_special(11, colors[0]))
sequences.append(set_special(12, colors[15]))
sequences.append(set_special(13, colors[15]))
sequences.append(set_special(14, colors[0]))
# Set a blank color that isn"t affected by bold highlighting.
sequences.append(set_special(66, colors[0]))
# This escape sequence doesn"t work in VTE terminals.
if not vte:
sequences.append(set_special(708, colors[0]))
# 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
[util.save_file("".join(sequences), term) for term in terminals]
print("colors: Set terminal 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)

12
pywal/settings.py Executable file
View File

@ -0,0 +1,12 @@
"""
Global Constants.
"""
import pathlib
__version__ = "0.2.0"
# Internal variables.
COLOR_COUNT = 16
CACHE_DIR = pathlib.Path.home() / ".cache/wal/"

42
pywal/util.py Executable file
View File

@ -0,0 +1,42 @@
"""
Misc helper functions.
"""
import os
import pathlib
import subprocess
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_dir(directory):
"""Alias to create the cache dir."""
pathlib.Path(directory).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 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)

View File

@ -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()

86
pywal/wallpaper.py Executable file
View File

@ -0,0 +1,86 @@
"""Set the wallpaper."""
import os
import shutil
import subprocess
from pywal import util
def get_desktop_env():
"""Identify the current running desktop environment."""
desktop = os.environ.get("XDG_CURRENT_DESKTOP")
if desktop:
return desktop
desktop = os.environ.get("DESKTOP_SESSION")
if desktop:
return desktop
desktop = os.environ.get("GNOME_DESKTOP_SESSION_ID")
if desktop:
return "GNOME"
desktop = os.environ.get("MATE_DESKTOP_SESSION_ID")
if desktop:
return "MATE"
def xfconf(path, img):
"""Call xfconf to set the wallpaper on XFCE."""
util.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

View File

@ -11,7 +11,7 @@ DESC = (
DESC = "".join(DESC) DESC = "".join(DESC)
VERSION = pywal.wal.__version__ VERSION = pywal.__version__
DOWNLOAD_URL = f"https://github.com/dylanaraps/pywal/archive/{VERSION}.tar.gz" DOWNLOAD_URL = f"https://github.com/dylanaraps/pywal/archive/{VERSION}.tar.gz"