#!/usr/bin/env python3 # # talideon-wallpaper # by Keith Gaughan # # A pipemenu script for Openbox for selecting and setting the current # wallpaper. # # Copyright (c) Keith Gaughan, 2008. # All Rights Reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS "AS IS" AND ANY # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE # DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # This license is subject to the laws and courts of the Republic of Ireland. # import os, sys from os import path from sys import argv try: from xml.etree import cElementTree as et except: from xml.etree import ElementTree as et FALLBACK_SETTERS = ["hsetroot -center"] SETTINGS = path.expanduser("~/.config/talideon.com/wallpaper") WP_LINK = path.join(SETTINGS, "current") def which(name): """ Finds the path of some named executable available on PATH. """ env_path = os.environ.get("PATH") if env_path: for dirname in env_path.split(os.pathsep): executable = path.join(dirname, name) if path.isfile(executable): return executable return None def get_setters(): """ Loads the list of all wallpaper setting commands. """ setters = [] setters_path = path.join(SETTINGS, "setters") if path.isfile(setters_path): try: handle = open(setters_path, "r") for line in handle: line = line.strip() if line != "" and line[0] != "#": setters.append(line) finally: handle.close() setters.extend(FALLBACK_SETTERS) return setters def show_wallpaper(): """ Gets a wallpaper setter to set the backdrop on the root window. """ for setter in get_setters(): parts = setter.split(" ", 2) location = which(parts[0]) if location is not None: parts[0] = location parts.append(path.realpath(WP_LINK)) os.spawnvpe(os.P_NOWAIT, location, parts, os.environ) return def set_wallpaper(wallpaper): """ Records the user's wallpaper selection. """ if path.isfile(wallpaper) and wallpaper != WP_LINK: os.unlink(WP_LINK) os.symlink(wallpaper, WP_LINK) def generate_directory_menu(dirname, tree): """ Generates the Openbox menuitems for a given directory. """ for name in sorted(os.listdir(dirname)): full_path = path.join(dirname, name) if path.isfile(full_path): tree.start("item", {"label": name[: name.rfind(".")]}) tree.start("action", {"name": "Execute"}) tree.start("execute") tree.data("%s '%s'" % (argv[0], full_path)) tree.end("execute") tree.end("action") tree.end("item") # Unfortunately, submenus, either as pipemenus or directly embedded # in a pipemenu, aren't allowed, but we'll leave this in anyway as # if/when it does, it'll be a nice hidden bonus feature. elif path.isdir(full_path): tree.start("menu", {"label": name}) generate_directory_menu(full_path, tree) tree.end("menu") def generate_pipemenu(dirname): """ Generates a pipemenu for a given directory. """ tree = et.TreeBuilder() tree.start("openbox_pipe_menu") generate_directory_menu(dirname, tree) return et.tostring(tree.close(), "UTF-8") def bad_path(): """ Generates a pipemenu indicating that the path given was not a valid one. """ tree = et.TreeBuilder() tree.start("openbox_pipe_menu") tree.start("item", {"label": "Bad path"}) return et.tostring(tree.close(), "UTF-8") if __name__ == "__main__": if not path.exists(SETTINGS): os.makedirs(SETTINGS) if len(argv) == 1: # With no args, the currently selected wallpaper is rendered. show_wallpaper() elif len(argv) >= 2: if path.isdir(argv[1]): # With one arg that' a directory, a pipemenu of that directory's # contents is generated. print(generate_pipemenu(argv[1])) elif path.isfile(argv[1]): # With one arg that's a file, that file is make the current # wallpaper. set_wallpaper(path.realpath(argv[1])) show_wallpaper() else: print(bad_path()) print("Bad path.", file=sys.stderr)