diff options
Diffstat (limited to 'python/openbox-shutdown.py')
-rwxr-xr-x | python/openbox-shutdown.py | 190 |
1 files changed, 190 insertions, 0 deletions
diff --git a/python/openbox-shutdown.py b/python/openbox-shutdown.py new file mode 100755 index 0000000..cfdd67b --- /dev/null +++ b/python/openbox-shutdown.py @@ -0,0 +1,190 @@ +#!/usr/bin/env python +""" + +shutdown script for Openbox with configurable buttons and actions +needs pygtk for gui +""" + +# standard stuff +import os +import re +import sys + +# gui modules +try: + import gtk + import pygtk +except ImportError: + sys.stderr.write('pygtk is needed for using this script') + sys.exit(1) + +if sys.version_info < (2, 5, 0): + sys.stderr.write('Python 2.5.0 or higher is needed') + sys.exit(1) + +# a simple parser for the configuration +class ConfigParser(dict): + """ + ConfigParser(file) -> dict + + reads file and creates dict object containing corresponding + configuration + """ + + def __init__(self, filename): + self._section_match_regexp = re.compile(r'\[(\w+)\]') + self._key_val_match_regexp = re.compile(r'\s*=\s*') + self._comment_remov_regexp = re.compile(r'#.*') + try: + config_handle = open(filename, 'r') + except IOError: + sys.stderr.write('Could not read %s. Aborting ...\n' % filename) + sys.exit(1) + linecount = 0 + for line in config_handle.readlines(): + linecount += 1 + line = self._comment_remov_regexp.sub('', line.strip()) + if len(line) == 0: + continue + if self._section_match_regexp.match(line): + section = self._section_match_regexp.match(line).groups()[0] + self[section] = {} + continue + try: + (key, value) = self._key_val_match_regexp.split(line) + except ValueError: + sys.stderr.write('Syntax error in line %d of %s.' % (linecount, + filename)) + sys.exit(1) + if key == 'command' and not key in self[section]: + self[section][key] = [value] + continue + if key in self[section] and key == 'command': + self[section][key].append(value) + else: + self[section][key] = value + + def check(self): + """ + checks if configuration is complete + """ + for section in self: + for needed_key in ['command', 'image', 'info_text', 'label']: + if not needed_key in self[section]: + sys.stderr.write('Missing option %s in %s.' % (needed_key, section)) + sys.exit(1) + +# the main class for this script +class OpenBoxShutdown(object): + """ + main class for this script + + reads configuration and displays buttons as requested + + on click, the specified actions are made + """ + + def __init__(self, basedir): + self._config = ConfigParser(os.path.join(basedir, 'openbox-shutdown.conf')) + self._config.check() + # button box on top for the action buttons + button_box = gtk.HButtonBox() + for key in self._config: + button_box.pack_start(self._create_button(key, + self._config[key]['label'], + self._config[key]['info_text'], + self._config[key]['image'])) + button_box.show() + # create cancel button + cancel_button = gtk.Button(stock = gtk.STOCK_CANCEL) + cancel_button.connect('clicked', self._click_callback, 'cancel') + cancel_button.show() + # label widget for small hints + self._label = gtk.Label() + self._label.show() + # frame widget to contain label + frame = gtk.Frame() + frame.set_shadow_type(gtk.SHADOW_NONE) + frame.add(self._label) + frame.show() + # area containing hints and cancel button + action_area = gtk.HBox() + action_area.pack_end(cancel_button, expand=False) + action_area.pack_end(frame) + action_area.show() + # box containing button box and action area + vbox = gtk.VBox() + vbox.pack_start(button_box) + vbox.pack_end(action_area) + vbox.show() + # the main window with all widgets + # always on top and on all desktops + window = gtk.Window() + window.set_position('center') + window.set_decorated(False) + window.stick() + window.set_keep_above(True) + window.set_skip_pager_hint(True) + window.set_skip_taskbar_hint(True) + window.add(vbox) + window.show() + # give control to gtk + gtk.main() + + def _click_callback(self, event, action): + """ + _click_callback(event, action) + + executes commands on button click + """ + gtk.main_quit() + if action == 'cancel': + sys.exit(0) + for command in self._config[action]['command']: + os.system(command) + + def _create_button(self, key, label_text, info_text, image_file): + """ + _create_button(key, label, info, image) -> button + + creates a button widget with key (used for handling actions), + a label for the button, a small text as hint and an image + """ + button = gtk.Button() + if label_text != 'None': + button.set_label(label_text) + if image_file != 'None': + button.set_image(self._create_image(image_file)) + button.set_image_position(gtk.POS_TOP) + button.connect('clicked', self._click_callback, key) + button.connect('leave', lambda event: self._label.set_text('')) + button.connect('enter', self._set_label, info_text) + button.show() + return button + + def _create_image(self, image_file): + """ + _create_image(image) -> image + + creates an image widget from the specified file + """ + image = gtk.Image() + image.set_from_file(image_file) + return image + + def _set_label(self, event, info_text): + """ + _set_label(event, info_text) + + set label on entering the widget + """ + if info_text != 'None': + self._label.set_markup('<span size="smaller">%s</span>' % info_text) + +# start the script if called standalone +if __name__ == '__main__': + # get the real path for the configuration file + conf_path = os.path.realpath(os.path.dirname(os.readlink(__file__))) \ + if os.path.islink(__file__) \ + else os.path.realpath(os.path.dirname(__file__)) + shutdown = OpenBoxShutdown(conf_path) |