mirror of
https://github.com/grassmunk/Chicago95.git
synced 2025-09-22 01:08:42 +02:00
pluslib(fix):
- Added logic to apply the wallpaper to all the monitors and workspaces - Fixed a breaking bug where icons were not generated as the folders were iterated and not their contents, causing mogrify to throw an error and break the script - Same for the cursors
This commit is contained in:
parent
bdf5cf36a1
commit
66f41bf6c4
314
Plus/pluslib.py
314
Plus/pluslib.py
@ -885,8 +885,8 @@ class ChicagoPlus:
|
||||
os.mkdir(self.folder_names[i])
|
||||
|
||||
def create_icons(self, create_48_document_icon = True):
|
||||
self.logger.info("Creating new icons in {}".format(self.folder_names['icons']))
|
||||
|
||||
self.logger.info(f"Creating new icons in {self.folder_names['icons']}")
|
||||
|
||||
svg_file_names = {}
|
||||
png_file_names = {
|
||||
"my_computer" : "user-home.png",
|
||||
@ -897,101 +897,108 @@ class ChicagoPlus:
|
||||
}
|
||||
|
||||
for i in png_file_names:
|
||||
svg_file_names[i] = png_file_names[i].replace(".png",".svg")
|
||||
svg_file_names[i] = png_file_names[i].replace(".png", ".svg")
|
||||
|
||||
for iconname in self.theme_config['icons']:
|
||||
self.logger.debug(f"Processing icon: {iconname}")
|
||||
self.logger.info(f"Processing icon: {iconname}")
|
||||
|
||||
if not self.theme_config['icons'][iconname]:
|
||||
self.logger.debug("{:<21} | Icon does not exist in this theme".format(iconname))
|
||||
self.logger.warning(f"{iconname:<21} | Icon does not exist in this theme")
|
||||
continue
|
||||
|
||||
icon_sizes = [16,22,24,32,48]
|
||||
icon_sizes = [16, 22, 24, 32, 48]
|
||||
|
||||
filename = self.theme_config['icons'][iconname]['filename']
|
||||
index = self.theme_config['icons'][iconname]['index']
|
||||
path = self.theme_config['icons'][iconname]['path']
|
||||
filetype = self.theme_config['icons'][iconname]['type']
|
||||
|
||||
self.logger.debug(f"Icon details - Name: {filename}, Index: {index}, Path: {path}, Type: {filetype}")
|
||||
|
||||
if not path:
|
||||
self.logger.error("{:<21} | {} does not exist in this theme".format(iconname, filename))
|
||||
self.logger.warning(f"{iconname:<21} | {filename} does not exist in this theme")
|
||||
continue
|
||||
|
||||
|
||||
if filetype not in ['dll', 'icl', 'ico', 'bmp']:
|
||||
# wut
|
||||
self.logger.error("File type {} not supported: {}".format(filetype, filename))
|
||||
self.logger.warning(f"File type {filetype} not supported: {filename}")
|
||||
continue
|
||||
|
||||
self.logger.info("{:<21} | {}".format(iconname, filename))
|
||||
|
||||
self.logger.info(f"{iconname:<21} | {filename}")
|
||||
|
||||
if filetype in ['dll', 'icl']:
|
||||
# Get the icons stored in the DLL
|
||||
self.logger.debug("{:<21} | Icons are stored in ICL file {}".format("", filename, path))
|
||||
icon_files = self.extract_icons_from_dll(path)
|
||||
|
||||
|
||||
else:
|
||||
self.logger.debug("{:<21} | Icons are stored in ICO file {} {}".format("", filename,path))
|
||||
self.logger.debug(f"{iconname:<21} | Icons are stored in ICO file {filename} {path}")
|
||||
icon_files = self.extract_ico(path)
|
||||
if icon_files == 'bmp':
|
||||
filetype = 'bmp'
|
||||
|
||||
if not icon_files:
|
||||
self.logger.error("Not a valid icon file: {}".format(self.theme_config['icons'][iconname]))
|
||||
self.logger.error(f"Not a valid icon file: {self.theme_config['icons'][iconname]}")
|
||||
continue
|
||||
|
||||
# If the icons exist at various sizes, write them and convert them instead of scaling the largest one
|
||||
for size in icon_sizes:
|
||||
self.logger.debug("{:<21} | Searching for icon size: {} in {}".format("", size, filename))
|
||||
self.logger.debug(f"{iconname:<21} | Searching for icon size: {size} in {filename}")
|
||||
|
||||
if filetype in ['dll','icl']:
|
||||
if filetype in ['dll', 'icl']:
|
||||
icon_filename, icon_file = self.get_icons_size_dll(icon_files, index, size)
|
||||
elif filetype in 'ico':
|
||||
elif filetype == 'ico':
|
||||
icon_filename, icon_file = self.get_icons_size_ico(icon_files, size)
|
||||
else:
|
||||
icon_filename = False
|
||||
if icon_filename:
|
||||
icon_sizes.remove(size)
|
||||
f = open(self.folder_names['icons']+icon_filename,"wb")
|
||||
f.write(icon_file)
|
||||
f.close()
|
||||
sized_target = self.folder_names['icons']+"places/"+str(size)+"/"+png_file_names[iconname]
|
||||
self.logger.debug("{:<21} | Creating: {} {} {}".format("", size, self.folder_names['icons']+icon_filename, sized_target))
|
||||
self.convert_ico_files(self.folder_names['icons']+icon_filename, sized_target)
|
||||
destination = os.path.join(self.folder_names['icons'], icon_filename)
|
||||
with open(destination, "wb") as f:
|
||||
f.write(icon_file)
|
||||
sized_target = os.path.join(
|
||||
self.folder_names['icons'], "places", str(size), png_file_names[iconname]
|
||||
)
|
||||
self.logger.debug(f"{iconname:<21} | Creating: {size} {destination} {sized_target}")
|
||||
self.convert_ico_files(destination, sized_target)
|
||||
|
||||
# Now that we're done, get the largest file and use that for the rest
|
||||
if filetype in ['dll', 'icl']:
|
||||
|
||||
icon_filename, icon_file = self.get_largest_icon_dll(icon_files, index)
|
||||
elif filetype in 'ico':
|
||||
elif filetype == 'ico':
|
||||
icon_filename, icon_file = self.get_largest_icon_ico(icon_files, size)
|
||||
|
||||
|
||||
if filetype in ['dll', 'icl', 'ico'] and not isinstance(icon_file, str):
|
||||
f = open(self.folder_names['icons']+icon_filename,"wb")
|
||||
f.write(icon_file)
|
||||
f.close()
|
||||
destination = os.path.join(self.folder_names['icons'], icon_filename)
|
||||
with open(destination, "wb") as f:
|
||||
f.write(icon_file)
|
||||
else:
|
||||
shutil.copyfile(path, self.folder_names['icons']+icon_filename)
|
||||
|
||||
|
||||
svg_icon_file = self.convert_icon(self.folder_names['icons'], self.folder_names['icons']+icon_filename)
|
||||
for size in icon_sizes:
|
||||
if size <= 32 and iconname == "documents_ico" and not create_48_document_icon:
|
||||
continue
|
||||
sized_target = self.folder_names['icons']+"places/"+str(size)+"/"+png_file_names[iconname]
|
||||
self.logger.debug("{:<21} | Creating: {} {} {}".format("", size, svg_icon_file, sized_target))
|
||||
self.convert_to_png_with_inkscape( svg_icon_file, size, sized_target)
|
||||
destination = os.path.join(self.folder_names['icons'], os.path.basename(icon_filename))
|
||||
shutil.copyfile(path, destination)
|
||||
|
||||
scaled_target = self.folder_names['icons']+"places/scalable/"+svg_file_names[iconname]
|
||||
svg_icon_file = self.convert_icon(self.folder_names['icons'], destination)
|
||||
for size in icon_sizes:
|
||||
if size <= 32 and iconname == "documents_ico" and not create_48_document_icon:
|
||||
continue
|
||||
sized_target = os.path.join(
|
||||
self.folder_names['icons'], "places", str(size), png_file_names[iconname]
|
||||
)
|
||||
self.logger.debug(f"{iconname:<21} | Creating: {size} {svg_icon_file} {sized_target}")
|
||||
self.convert_to_png_with_inkscape(svg_icon_file, size, sized_target)
|
||||
|
||||
scaled_target = os.path.join(
|
||||
self.folder_names['icons'], "places", "scalable", svg_file_names[iconname]
|
||||
)
|
||||
shutil.copy(svg_icon_file, scaled_target)
|
||||
|
||||
# Update index.theme
|
||||
self.logger.debug("Updating icon index.theme file")
|
||||
icon_theme_config = configparser.RawConfigParser(interpolation=None)
|
||||
icon_theme_config.optionxform = str
|
||||
icon_theme_config.read(self.folder_names['icons']+"/index.theme")
|
||||
icon_theme_config.set("Icon Theme","Name",self.index_theme_name)
|
||||
with open(self.folder_names['icons']+"/index.theme", 'w') as configfile:
|
||||
icon_theme_config.write(configfile, space_around_delimiters=False)
|
||||
icon_theme_config.read(os.path.join(self.folder_names['icons'], "index.theme"))
|
||||
icon_theme_config.set("Icon Theme", "Name", self.index_theme_name)
|
||||
with open(os.path.join(self.folder_names['icons'], "index.theme"), 'w') as configfile:
|
||||
icon_theme_config.write(configfile, space_around_delimiters=False)
|
||||
|
||||
|
||||
def create_cursors(self):
|
||||
self.logger.info("Creating new xcursors in {}".format(self.folder_names['cursors']))
|
||||
@ -1799,25 +1806,64 @@ class ChicagoPlus:
|
||||
}
|
||||
|
||||
|
||||
for i in ['gtk-3.0/assets/','gtk-3.24/assets/','gtk-3.0/scrollbar/','gtk-3.24/scrollbar/']:
|
||||
|
||||
folder = path + i
|
||||
for i in ['gtk-3.0/assets/', 'gtk-3.24/assets/', 'gtk-3.0/scrollbar/', 'gtk-3.24/scrollbar/']:
|
||||
folder = path + i
|
||||
for asset in os.listdir(folder):
|
||||
if not asset.startswith("status") and not asset.startswith("branding"):
|
||||
self.logger.debug("mogrifying {} ({} {} {} {} {} {})".format(asset, ButtonDKShadow, ButtonLight, ButtonShadow, ButtonHilight, ButtonFace, ButtonText))
|
||||
asset_path = os.path.join(folder, asset) # Get full path of the asset
|
||||
|
||||
# If the asset is a directory, iterate over its contents
|
||||
if os.path.isdir(asset_path):
|
||||
self.logger.info(f"Entering directory: {asset_path}")
|
||||
for sub_asset in os.listdir(asset_path):
|
||||
sub_asset_path = os.path.join(asset_path, sub_asset)
|
||||
if os.path.isfile(sub_asset_path): # Ensure it's a valid file
|
||||
self.logger.debug(
|
||||
f"mogrifying {sub_asset} in {asset_path} "
|
||||
f"({ButtonDKShadow}, {ButtonLight}, {ButtonShadow}, "
|
||||
f"{ButtonHilight}, {ButtonFace}, {ButtonText})"
|
||||
)
|
||||
args = [
|
||||
mogrify_path,
|
||||
'-fill', ButtonDKShadow, '-opaque', originals['ButtonDKShadow'],
|
||||
'-fill', ButtonLight, '-opaque', originals['ButtonLight'],
|
||||
'-fill', ButtonShadow, '-opaque', originals['ButtonShadow'],
|
||||
'-fill', ButtonHilight, '-opaque', originals['ButtonHilight'],
|
||||
'-fill', ButtonFace, '-opaque', originals['ButtonFace'],
|
||||
'-fill', ButtonText, '-opaque', originals['ButtonText'],
|
||||
'-quiet',
|
||||
sub_asset_path
|
||||
]
|
||||
|
||||
try:
|
||||
subprocess.check_call(args)
|
||||
except subprocess.CalledProcessError as e:
|
||||
self.logger.error(f"Failed to process file {sub_asset_path}: {e}")
|
||||
else:
|
||||
self.logger.warning(f"Skipping non-file in directory: {sub_asset_path}")
|
||||
continue # Skip further processing of the directory itself
|
||||
|
||||
# Process regular files in the current folder
|
||||
if not asset.startswith("status") and not asset.startswith("branding"):
|
||||
self.logger.debug(
|
||||
f"mogrifying {asset} ({ButtonDKShadow}, {ButtonLight}, {ButtonShadow}, "
|
||||
f"{ButtonHilight}, {ButtonFace}, {ButtonText})"
|
||||
)
|
||||
args = [
|
||||
mogrify_path,
|
||||
'-fill', ButtonDKShadow, '-opaque', originals['ButtonDKShadow'],
|
||||
'-fill', ButtonLight, '-opaque', originals['ButtonLight'],
|
||||
'-fill', ButtonShadow, '-opaque', originals['ButtonShadow'],
|
||||
'-fill', ButtonHilight, '-opaque', originals['ButtonHilight'],
|
||||
'-fill', ButtonFace, '-opaque', originals['ButtonFace'],
|
||||
'-fill', ButtonText, '-opaque', originals['ButtonText'],
|
||||
'-quiet',
|
||||
folder+asset
|
||||
mogrify_path,
|
||||
'-fill', ButtonDKShadow, '-opaque', originals['ButtonDKShadow'],
|
||||
'-fill', ButtonLight, '-opaque', originals['ButtonLight'],
|
||||
'-fill', ButtonShadow, '-opaque', originals['ButtonShadow'],
|
||||
'-fill', ButtonHilight, '-opaque', originals['ButtonHilight'],
|
||||
'-fill', ButtonFace, '-opaque', originals['ButtonFace'],
|
||||
'-fill', ButtonText, '-opaque', originals['ButtonText'],
|
||||
'-quiet',
|
||||
asset_path
|
||||
]
|
||||
subprocess.check_call(args)
|
||||
|
||||
try:
|
||||
subprocess.check_call(args)
|
||||
except subprocess.CalledProcessError as e:
|
||||
self.logger.error(f"Failed to process file {asset_path}: {e}")
|
||||
|
||||
|
||||
#### Icon/Cursor Functions
|
||||
@ -2943,33 +2989,91 @@ class ChicagoPlus:
|
||||
shutil.rmtree(install_theme_dir, ignore_errors=True)
|
||||
shutil.copytree(self.folder_names['sounds'],install_theme_dir,symlinks=True,ignore_dangling_symlinks=True)
|
||||
|
||||
|
||||
def install_wallpaper(self, os_wallpaper_dir=str(Path.home())+"/Pictures/"):
|
||||
self.logger.info("Installing wallpaper")
|
||||
def install_wallpaper(self, os_wallpaper_dir=str(Path.home()) + "/Pictures/"):
|
||||
"""
|
||||
Install the wallpaper by copying it to the designated directory and applying it
|
||||
to all monitors and workspaces dynamically.
|
||||
"""
|
||||
self.logger.info("Installing and applying wallpaper.")
|
||||
|
||||
# Ensure the destination directory exists
|
||||
if not os.path.exists(os_wallpaper_dir):
|
||||
self.logger.error("Theme install directory does not exists: {}".format(os_wallpaper_dir))
|
||||
self.logger.error(f"Theme install directory does not exist: {os_wallpaper_dir}")
|
||||
return
|
||||
|
||||
if (self.theme_config['wallpaper']['theme_wallpaper'] and
|
||||
self.theme_config['wallpaper']['theme_wallpaper']['wallpaper'] and
|
||||
self.theme_config['wallpaper']['theme_wallpaper']['path']):
|
||||
self.logger.debug("Copying {} to {}".format(self.theme_config['wallpaper']['theme_wallpaper']['path'], os_wallpaper_dir + self.theme_config['wallpaper']['theme_wallpaper']['new_filename']))
|
||||
try:
|
||||
shutil.copy(self.theme_config['wallpaper']['theme_wallpaper']['path'], os_wallpaper_dir + self.theme_config['wallpaper']['theme_wallpaper']['new_filename'])
|
||||
except:
|
||||
self.logger.error("Could not install wallpaper to {}".format(os_wallpaper_dir))
|
||||
# Install the main wallpaper
|
||||
if (self.theme_config['wallpaper']['theme_wallpaper'] and
|
||||
self.theme_config['wallpaper']['theme_wallpaper']['wallpaper'] and
|
||||
self.theme_config['wallpaper']['theme_wallpaper']['path']):
|
||||
|
||||
wallpaper_path = os.path.join(os_wallpaper_dir, self.theme_config['wallpaper']['theme_wallpaper']['new_filename'])
|
||||
self.logger.debug(f"Copying wallpaper from {self.theme_config['wallpaper']['theme_wallpaper']['path']} to {wallpaper_path}")
|
||||
try:
|
||||
shutil.copy(self.theme_config['wallpaper']['theme_wallpaper']['path'], wallpaper_path)
|
||||
self.logger.info(f"Wallpaper successfully installed to {wallpaper_path}")
|
||||
except Exception as e:
|
||||
self.logger.error(f"Could not install wallpaper to {wallpaper_path}: {e}")
|
||||
return
|
||||
|
||||
# Apply the wallpaper to all monitors and workspaces
|
||||
self.apply_wallpaper_to_all_monitors(wallpaper_path, self.theme_config['wallpaper']['theme_wallpaper']['wallpaperstyle'])
|
||||
|
||||
# Install additional wallpapers
|
||||
if self.theme_config['wallpaper']['extra_wallpapers']:
|
||||
for wallpaper in self.theme_config['wallpaper']['extra_wallpapers']:
|
||||
self.logger.debug("Copying {} to {}".format(wallpaper, os_wallpaper_dir))
|
||||
try:
|
||||
shutil.copy(wallpaper, os_wallpaper_dir)
|
||||
except:
|
||||
self.logger.error("Could not install wallpaper to {}".format(wallpaper))
|
||||
raise
|
||||
dest = os.path.join(os_wallpaper_dir, os.path.basename(wallpaper))
|
||||
self.logger.debug(f"Copying extra wallpaper from {wallpaper} to {dest}")
|
||||
try:
|
||||
shutil.copy(wallpaper, dest)
|
||||
self.logger.info(f"Extra wallpaper successfully installed to {dest}")
|
||||
except Exception as e:
|
||||
self.logger.error(f"Could not install extra wallpaper to {dest}: {e}")
|
||||
|
||||
def apply_wallpaper_to_all_monitors(self, wallpaper_path, wallpaper_style):
|
||||
"""
|
||||
Apply the wallpaper to all monitors and workspaces dynamically.
|
||||
|
||||
Args:
|
||||
wallpaper_path (str): Path to the wallpaper image.
|
||||
wallpaper_style (int): Wallpaper style (e.g., 0 = centered, 2 = stretched).
|
||||
"""
|
||||
channel = "xfce4-desktop"
|
||||
self.logger.info(f"Applying wallpaper '{wallpaper_path}' to all monitors and workspaces.")
|
||||
|
||||
try:
|
||||
xfconf_query_path = subprocess.check_output(["which", "xfconf-query"]).strip()
|
||||
properties = subprocess.check_output(
|
||||
[xfconf_query_path, "--channel", channel, "--list"],
|
||||
universal_newlines=True
|
||||
).splitlines()
|
||||
|
||||
# Filter relevant properties for workspaces and monitors
|
||||
for prop in properties:
|
||||
if "workspace" in prop and "last-image" in prop:
|
||||
workspace_base = prop.rsplit("/", 1)[0] # Get base workspace path
|
||||
last_image_property = f"{workspace_base}/last-image"
|
||||
image_style_property = f"{workspace_base}/image-style"
|
||||
|
||||
# Set wallpaper
|
||||
self.logger.debug(f"Setting wallpaper for {last_image_property} to {wallpaper_path}")
|
||||
subprocess.check_call(
|
||||
[xfconf_query_path, "--channel", channel, "--property", last_image_property, "--set", wallpaper_path]
|
||||
)
|
||||
|
||||
# Set wallpaper style
|
||||
self.logger.debug(f"Setting image style for {image_style_property} to {wallpaper_style}")
|
||||
subprocess.check_call(
|
||||
[xfconf_query_path, "--channel", channel, "--property", image_style_property, "--set", str(wallpaper_style)]
|
||||
)
|
||||
|
||||
self.logger.info("Wallpaper applied successfully.")
|
||||
|
||||
except subprocess.CalledProcessError as e:
|
||||
self.logger.error(f"Failed to set wallpaper properties: {e}")
|
||||
except Exception as e:
|
||||
self.logger.error(f"Unexpected error while applying wallpaper: {e}")
|
||||
|
||||
## Enable the theme in XFCE
|
||||
## Enable the theme in XFCE
|
||||
def enable_theme(self, cursors=True, icons=True, wallpaper=True, sounds=True, colors=True, fonts=True, screensaver=True):
|
||||
|
||||
self.logger.info("Enabling {}".format(self.theme_name))
|
||||
@ -3013,8 +3117,6 @@ class ChicagoPlus:
|
||||
self.xfconf_query('xfce4-desktop', '/backdrop/screen0/monitor0/workspace0/image-style', "4")
|
||||
else:
|
||||
self.logger.debug("Wallpaper failed to install")
|
||||
|
||||
|
||||
|
||||
if sounds:
|
||||
self.logger.info("Enabling New Sounds")
|
||||
@ -3025,6 +3127,8 @@ class ChicagoPlus:
|
||||
self.xfconf_query('xsettings', '/Net/ThemeName', self.theme_name+"_Theme")
|
||||
if screensaver:
|
||||
self.logger.info("Screensavers require manual install. See the script in {}".format(self.folder_names['screensaver']))
|
||||
|
||||
self.logger.info("Theme installation completed successfully!")
|
||||
|
||||
|
||||
def enable_fonts(self):
|
||||
@ -3147,19 +3251,47 @@ class ChicagoPlus:
|
||||
self.xfconf_query('xfwm4', '/general/title_font', font + ' 8')
|
||||
|
||||
## Enable Helper functions
|
||||
def xfconf_query(self, channel, prop, new_value):
|
||||
def xfconf_query(self, channel, prop_base, new_value):
|
||||
"""
|
||||
Dynamically sets xfconf properties for all monitors and workspaces.
|
||||
|
||||
:param channel: The xfconf channel (e.g., "xfce4-desktop").
|
||||
:param prop_base: Base property path (e.g., "/backdrop/screen0").
|
||||
:param new_value: The new value to set for the property.
|
||||
"""
|
||||
try:
|
||||
xfconf_query_path = subprocess.check_output(["which", "xfconf-query"]).strip()
|
||||
self.logger.debug("Changing xfconf setting {}/{} to {}".format(channel, prop, new_value))
|
||||
args = [
|
||||
xfconf_query_path,
|
||||
"--channel", channel,
|
||||
"--property", prop,
|
||||
"--set", new_value
|
||||
]
|
||||
subprocess.check_call(args, stdout=subprocess.DEVNULL)
|
||||
self.logger.debug(f"Changing xfconf setting {channel}/{prop_base} to {new_value}")
|
||||
|
||||
# Retrieve all properties in the channel
|
||||
props = subprocess.check_output(
|
||||
[xfconf_query_path, "--channel", channel, "--list"],
|
||||
universal_newlines=True
|
||||
).splitlines()
|
||||
|
||||
# Filter relevant properties for monitors and workspaces
|
||||
for prop in props:
|
||||
if prop.startswith(prop_base):
|
||||
self.logger.debug(f"Found property: {prop}")
|
||||
|
||||
# Update the property value
|
||||
args = [
|
||||
xfconf_query_path,
|
||||
"--channel", channel,
|
||||
"--property", prop,
|
||||
"--set", new_value
|
||||
]
|
||||
try:
|
||||
subprocess.check_call(args, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
||||
self.logger.info(f"Set {prop} to {new_value}")
|
||||
except subprocess.CalledProcessError as e:
|
||||
self.logger.error(f"Failed to set {prop}: {e}")
|
||||
|
||||
except subprocess.CalledProcessError:
|
||||
self.logger.info("xfconf not installed, enable theme manually")
|
||||
self.logger.error("xfconf-query not installed or not available. Enable theme manually.")
|
||||
except Exception as e:
|
||||
self.logger.error(f"Error setting xfconf property: {e}")
|
||||
|
||||
|
||||
def get_font_list(self):
|
||||
fc_list = subprocess.check_output(["which", "fc-list"]).strip()
|
||||
|
Loading…
x
Reference in New Issue
Block a user