Initial import
authorEnrico Zini <enrico@enricozini.org>
Sat, 13 Jun 2009 17:15:15 +0000 (01:15 +0800)
committerEnrico Zini <enrico@enricozini.org>
Sat, 13 Jun 2009 17:15:15 +0000 (01:15 +0800)
.gitignore [new file with mode: 0644]
plugins/debug.py [new file with mode: 0644]
run [new file with mode: 0755]
src/zavai [new file with mode: 0755]
zavai/__init__.py [new file with mode: 0644]
zavai/app.py [new file with mode: 0644]
zavai/conf.py [new file with mode: 0644]
zavai/menu.py [new file with mode: 0644]
zavai/plugins.py [new file with mode: 0644]
zavai/registry.py [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..c9b568f
--- /dev/null
@@ -0,0 +1,2 @@
+*.pyc
+*.swp
diff --git a/plugins/debug.py b/plugins/debug.py
new file mode 100644 (file)
index 0000000..0456830
--- /dev/null
@@ -0,0 +1,13 @@
+import zavai
+import gtk
+import sys
+
+def init(conf = None, registry = None, **kw):
+    debug = registry.menu("main.debug")
+
+    quit = gtk.Button("Quit")
+    quit.connect("clicked", gtk.main_quit)
+    debug.add_child(quit)
+
+    registry.menu("main").add_child(registry.menu_link("main.debug", "Debug"))
+
diff --git a/run b/run
new file mode 100755 (executable)
index 0000000..26c385c
--- /dev/null
+++ b/run
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+export PYTHONPATH=.
+export ZAVAI_CONFDIR=conf
+export ZAVAI_PLUGINS=plugins
+
+src/zavai --verbose "$@"
diff --git a/src/zavai b/src/zavai
new file mode 100755 (executable)
index 0000000..5993720
--- /dev/null
+++ b/src/zavai
@@ -0,0 +1,82 @@
+#!/usr/bin/python
+
+import sys
+import signal
+import optparse
+import gtk
+import dbus
+import dbus.mainloop.glib
+import zavai
+
+VERSION="0.1"
+
+def warning(*args):
+    sys.stderr.write(" ".join(map(str, args)) + "\n")
+def info(*args):
+    sys.stderr.write(" ".join(map(str, args)) + "\n")
+
+class Parser(optparse.OptionParser):
+    def __init__(self, *args, **kwargs):
+        # Yes, in 2009 optparse from the *standard library* still uses old
+        # style classes
+        optparse.OptionParser.__init__(self, *args, **kwargs)
+
+    def error(self, msg):
+        sys.stderr.write("%s: error: %s\n\n" % (self.get_prog_name(), msg))
+        self.print_help(sys.stderr)
+        sys.exit(2)
+
+parser = Parser(usage="usage: %prog [options]",
+                version="%prog "+ VERSION,
+                description="Simple interactive interface for the OpenMoko")
+parser.add_option("-v", "--verbose", action="store_true", help="verbose mode")
+
+(opts, args) = parser.parse_args()
+
+
+if not opts.verbose:
+    def info(*args):
+        pass
+
+# Read configuration
+info("Loading configuration")
+conf = zavai.read_config(nick="zavai")
+
+# Set up dbus
+dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+
+# Set up zavai
+registry = zavai.Registry()
+
+# Register main factories
+registry.register("conf", lambda *args, **kw: conf)
+registry.register("app", zavai.Zavai)
+registry.register("menu", zavai.Menu)
+
+# Load plugins
+info("Loading plugins")
+for p in zavai.load_plugins(nick="zavai"):
+    try:
+        p.init(conf = conf, registry = registry)
+    except Exception, e:
+        print >>sys.stderr, "Exception caught loading plugin %s: skipping plugin" % p
+        print >>sys.stderr, "Exception details:"
+        import traceback
+        details = traceback.format_exc()
+        print >>sys.stderr, "\t"+details.rstrip().replace("\n", "\n\t")
+
+# Shutdown the main loop on SIGINT
+def on_kill(signum, frame):
+    gtk.main_quit()
+signal.signal(signal.SIGINT, on_kill)
+signal.signal(signal.SIGTERM, on_kill)
+
+info("Starting")
+app = registry.resource("app")
+app.connect("destroy", gtk.main_quit)
+app.run()
+
+info("Shutting down")
+registry.shutdown()
+
+sys.exit(0)
diff --git a/zavai/__init__.py b/zavai/__init__.py
new file mode 100644 (file)
index 0000000..4e910d0
--- /dev/null
@@ -0,0 +1,5 @@
+from conf import read_config
+from plugins import load_plugins
+from registry import Registry, Resource
+from menu import Menu, MenuLink
+from app import Zavai
diff --git a/zavai/app.py b/zavai/app.py
new file mode 100644 (file)
index 0000000..c0161b7
--- /dev/null
@@ -0,0 +1,22 @@
+import sys
+import gtk
+
+class Zavai(gtk.Window):
+    def __init__(self, registry, name):
+        super(Zavai, self).__init__()
+        self.registry = registry
+        self.add(registry.menu("main"))
+
+    def show_widget(self, name):
+        widget = self.registry.get_existing(name)
+        if widget is None:
+            widget = self.registry.menu("main")
+        self.remove(self.get_child())
+        self.add(widget)
+        widget.show_all()
+
+    def run(self):
+        self.fullscreen()
+        self.show_all()
+        gtk.main()
+
diff --git a/zavai/conf.py b/zavai/conf.py
new file mode 100644 (file)
index 0000000..ba253a4
--- /dev/null
@@ -0,0 +1,33 @@
+import os
+import ConfigParser, StringIO
+
+def read_config(rootDir = None, defaults = None, nick="octofuss"):
+    """
+    Read octofuss configuration, returning a ConfigParser object
+    """
+    if rootDir == None:
+        rootDir = os.environ.get(nick.upper() + "_CONFDIR", "/etc/" + nick)
+    files = []
+    def trytouse(path):
+        if os.path.exists(path):
+            files.append(path)
+
+    # Start with the main config file
+    trytouse(os.path.join(rootDir, nick + ".conf"))
+
+    # Add snippets found in rc.d style directory
+    subdir = os.path.join(rootDir, nick + ".conf.d")
+    if os.path.isdir(subdir):
+        for file in sorted(os.listdir(subdir)):
+            if file.startswith('#'): continue
+            if file.startswith('.'): continue
+            if file.endswith('~'): continue
+            if file.endswith('.bak'): continue
+            trytouse(os.path.join(subdir, file))
+
+    config = ConfigParser.ConfigParser()
+    if defaults != None:
+        infile = StringIO.StringIO(defaults)
+        config.readfp(infile, "defaults")
+    config.read(files)
+    return config
diff --git a/zavai/menu.py b/zavai/menu.py
new file mode 100644 (file)
index 0000000..cf3d05a
--- /dev/null
@@ -0,0 +1,37 @@
+import sys
+import zavai
+import gtk
+
+class Menu(gtk.VBox, zavai.Resource):
+    def __init__(self, registry, name, *args, **kw):
+        super(Menu, self).__init__()
+        self.vbox = self
+
+        print >>sys.stderr, "PARENT?", name
+        parent = None
+        pos = name.rfind(".")
+        if pos != -1:
+            parent = name[:pos]
+            print >>sys.stderr, "PARENT IS", parent
+            if parent == "menu":
+                parent = None
+                print >>sys.stderr, "PARENT MAIN?"
+
+        if parent is not None:
+            print >>sys.stderr, "MAKE PARENT"
+            self.vbox = gtk.VBox()
+            self.pack_start(self.vbox)
+            self.pack_start(registry.menu_link(parent, "Back"), True, True)
+
+    def add_child(self, widget):
+        self.vbox.pack_start(widget, True, True)
+
+class MenuLink(gtk.Button, zavai.Resource):
+    def __init__(self, registry, targetName, label):
+        super(MenuLink, self).__init__(label)
+        self.target = "menu." + targetName
+        self.registry = registry
+        self.connect("clicked", self.on_click)
+
+    def on_click(self, *args):
+        self.registry.resource("app").show_widget(self.target)
diff --git a/zavai/plugins.py b/zavai/plugins.py
new file mode 100644 (file)
index 0000000..bfd512f
--- /dev/null
@@ -0,0 +1,39 @@
+#!/usr/bin/env python
+#
+#  File: plugins.py
+# 
+#  Copyright (C) 2008 Christopher R. Gabriel <cgabriel@truelite.it> 
+# 
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+# 
+
+import os
+import os.path
+import imp
+import sys
+
+def load_plugins(pluginpath=None, nick="octofuss"):
+       """return a list of all available plugins
+       in the given directory"""
+
+       if not pluginpath:
+               pluginpath = os.environ.get(nick.upper() + "_PLUGINS", "plugins")
+
+       # if the plugin path need to be auto-discovered
+       # starting from a specified module
+       #pluginpath = os.path.join(os.path.dirname(imp.find_module("octofussd")[1]), "extensions/")
+       #pluginpath = "."
+       pluginfiles = [fname[:-3] for fname in os.listdir(pluginpath) if fname.endswith(".py") and not fname.startswith(".") and not fname.endswith("~")]
+
+       for fname in pluginfiles:
+               oldpath = sys.path
+               try:
+                       sys.path.append(os.path.abspath(pluginpath))
+                       res = imp.load_source(fname, os.path.join(pluginpath, fname) + ".py")
+               finally:
+                       sys.path = oldpath
+               yield res
+                       
diff --git a/zavai/registry.py b/zavai/registry.py
new file mode 100644 (file)
index 0000000..fae2a63
--- /dev/null
@@ -0,0 +1,96 @@
+import zavai
+
+class Registry(object):
+    """Collection of resources.
+
+    Various factories can be registered by name on the registry. Then when an
+    object is requested for the first time, it is created using the factory.
+    When it is requested again, the existing object is reused.
+    """
+
+    def __init__(self):
+        self.factories = dict()
+        self.objects = dict()
+
+    def resource(self, name):
+        """Get a resource, instantiating it if it has not been done yet.
+
+        First it tries to use the factory registered with `name` itself. If it
+        fails, it tries to use the factory registered one level above (using
+        the dot '.' as a separator).
+
+        If no suitable factory has been found, returns None.
+        """
+        res = self.objects.get(name, None)
+        if res is None:
+            fac = self.factories.get(name, None)
+            if fac is None:
+                root = name
+                while True:
+                    pos = root.rfind(".")
+                    if pos == -1: break
+                    root = root[:pos]
+                    fac = self.factories.get(root, None)
+                if fac is None:
+                    return None
+            res = fac(self, name)
+            if res is not None:
+                self.objects[name] = res
+        return res
+
+    def menu(self, name):
+        """Get a menu resource, instantiating it if it has not been done yet.
+
+        All menu resources share the same factory, which builds zavai.Menu
+        objects.
+        """
+        return self.resource("menu." + name)
+
+    def menu_link(self, name, label):
+        """Return a MenuLink to the menu with the given name
+        """
+        return zavai.MenuLink(self, name, label)
+
+    def get_existing(self, name):
+        """Get a menu resource, but only if it has been already instantiated.
+
+        If the resource has not been instantiated yet, returns None.
+        """
+        return self.objects.get(name, None)
+
+    def register(self, name, factory):
+        """Register a factory for this registry.
+
+        Name is a name for this factory, like "menu.gps.monitor".
+
+        Factory is a function that creates a Resource object. The function will
+        be passed the Registry itself as the only parameter"""
+        if name in self.factories:
+            return KeyError("% is already registered as a factory", name)
+        self.factories[name] = factory
+
+    def shutdown(self):
+        """Shut down all objects in this Registry.
+
+        After shutting down, all objects cannot be used anymore"""
+        for o in self.objects.itervalues():
+            o.shutdown()
+        self.objects.clear()
+
+class Resource(object):
+    def __init__(self, registry, name, *args, **kw):
+        """The default constructor does nothing, but is there to eat the
+        parameters passed by Registry in case subclassers do not need a
+        constructor"""
+        pass
+
+    def shutdown(self):
+        """Shut down this resource.
+
+        Normally one does nothing here, but it is important to give resources a
+        chance to do cleanup when the program quits.
+
+        This can be used for tasks like closing the tags on a GPX track,
+        releasing a FSO resource, restoring mixer settings and so on.
+        """
+        pass