Index: mythtv/libs/libmyth/mythcontext.h
===================================================================
--- mythtv/libs/libmyth/mythcontext.h	(revision 7868)
+++ mythtv/libs/libmyth/mythcontext.h	(working copy)
@@ -12,7 +12,6 @@
 #include <qsocketdevice.h>
 #include <qstringlist.h>
 #include <qnetwork.h> 
-#include <qdeepcopy.h>
 #include <qmap.h>
 
 #include <cerrno>
@@ -20,6 +19,8 @@
 #include <sstream>
 #include <vector>
 
+#include "mythobservable.h"
+
 using namespace std;
 
 #if (QT_VERSION < 0x030100)
@@ -145,43 +146,7 @@
 /// Verbose helper function for ENO macro
 QString safe_eno_to_string(int errnum);
 
-/** \class MythEvent
- *  \brief This class is used as a container for messages.
- *
- *   MythEvents can be dispatched to all listeners by calling
- *   gContext->dispatch(MythEvent&) or gContext->dispatchNow(MythEvent&).
- *   The former is much preferred as it uses QApplication::postEvent()
- *   while the latter uses the blocking QApplication::sendEvent().
- */
-class MythEvent : public QCustomEvent
-{
-  public:
-    enum Type { MythEventMessage = (User + 1000) };
 
-    MythEvent(const QString lmessage) : QCustomEvent(MythEventMessage)
-    {
-        message = QDeepCopy<QString>(lmessage);
-        extradata = "empty";
-    }
-    MythEvent(const QString lmessage, const QStringList &lextradata)
-           : QCustomEvent(MythEventMessage)
-    {
-        message = QDeepCopy<QString>(lmessage);
-        extradata = lextradata;
-    }
-    
-    ~MythEvent() {}
-
-    const QString& Message() const { return message; }
-    const QString& ExtraData(int idx = 0) const { return extradata[idx]; } 
-    const QStringList& ExtraDataList() const { return extradata; } 
-    int ExtraDataCount() const { return extradata.size(); }
-
-  private:
-    QString message;
-    QStringList extradata;
-};
-
 /** \class MythPrivRequest
  *  \brief Container for requests that require privledge escalation.
  *
@@ -225,7 +190,7 @@
  *   It also contains support for database error printing, and
  *   database message logging.
  */
-class MythContext : public QObject
+class MythContext : public QObject, public MythObservable
 {
     Q_OBJECT
   public:
@@ -349,11 +314,6 @@
     QPixmap *LoadScalePixmap(QString filename, bool fromcache = true); 
     QImage *LoadScaleImage(QString filename, bool fromcache = true);
 
-    void addListener(QObject *obj);
-    void removeListener(QObject *obj);
-    void dispatch(MythEvent &e);
-    void dispatchNow(MythEvent &e);
-
     bool SendReceiveStringList(QStringList &strlist, bool quickTimeout = false);
 
     QImage *CacheRemotePixmap(const QString &url, bool reCache = false);
Index: mythtv/libs/libmyth/output.cpp
===================================================================
--- mythtv/libs/libmyth/output.cpp	(revision 7868)
+++ mythtv/libs/libmyth/output.cpp	(working copy)
@@ -6,6 +6,7 @@
 
 #include <cstdio>
 #include <qobject.h>
+#include <qapplication.h>
 
 #include "output.h"
 #include "visual.h"
@@ -15,40 +16,15 @@
     bufsize=0;
 }
 
-
 OutputListeners::~OutputListeners()
 {
 }
 
-
-void OutputListeners::addListener(QObject *o)
-{
-    if (listeners.find(o) == -1)
-	listeners.append(o);
-}
-
-
-void OutputListeners::removeListener(QObject *o)
-{
-    listeners.remove(o);
-}
-
-
-void OutputListeners::dispatch(OutputEvent &e)
-{
-    QObject *object = listeners.first();
-    while (object) {
-	QThread::postEvent(object, new OutputEvent(e));
-	object = listeners.next();
-    }
-}
-
-
 void OutputListeners::error(const QString &e) {
-    QObject *object = listeners.first();
+    QObject *object = firstListener();
     while (object) {
-	QThread::postEvent(object, new OutputEvent(e));
-	object = listeners.next();
+        QApplication::postEvent(object, new OutputEvent(e));
+        object = nextListener();
     }
 }
 
Index: mythtv/libs/libmyth/libmyth.pro
===================================================================
--- mythtv/libs/libmyth/libmyth.pro	(revision 7868)
+++ mythtv/libs/libmyth/libmyth.pro	(working copy)
@@ -21,7 +21,7 @@
 HEADERS += dbsettings.h screensaver-null.h output.h visual.h
 HEADERS += langsettings.h audiooutputnull.h
 HEADERS += DisplayResScreen.h util-x11.h mythdeque.h qmdcodec.h
-HEADERS += exitcodes.h virtualkeyboard.h
+HEADERS += exitcodes.h virtualkeyboard.h mythobservable.h mythevent.h
 
 SOURCES += dialogbox.cpp lcddevice.cpp mythcontext.cpp mythwidgets.cpp 
 SOURCES += oldsettings.cpp remotefile.cpp settings.cpp themedmenu.cpp
@@ -33,7 +33,7 @@
 SOURCES += dbsettings.cpp screensaver.cpp screensaver-null.cpp output.cpp
 SOURCES += langsettings.cpp mythdbcon.cpp audiooutputnull.cpp
 SOURCES += DisplayResScreen.cpp util-x11.cpp qmdcodec.cpp
-SOURCES += virtualkeyboard.cpp
+SOURCES += virtualkeyboard.cpp mythobservable.cpp
 
 INCLUDEPATH += ../libmythsamplerate ../libmythsoundtouch ../..
 DEPENDPATH += ../libmythsamplerate ../libmythsoundtouch
@@ -57,9 +57,10 @@
 inc.files += mythwidgets.h remotefile.h util.h oldsettings.h volumecontrol.h
 inc.files += settings.h uitypes.h xmlparse.h mythplugin.h mythdialogs.h
 inc.files += audiooutput.h inetcomms.h httpcomms.h mythmedia.h mythwizard.h
-inc.files += uilistbtntype.h generictree.h managedlist.h
+inc.files += uilistbtntype.h generictree.h managedlist.h observable.h
 inc.files += visual.h volumebase.h output.h langsettings.h qmdcodec.h
 inc.files += exitcodes.h mythconfig.h mythconfig.mak virtualkeyboard.h
+inc.files += mythevent.h mythobservable.h
 
 using_oss {
     DEFINES += USING_OSS
Index: mythtv/libs/libmyth/output.h
===================================================================
--- mythtv/libs/libmyth/output.h	(revision 7868)
+++ mythtv/libs/libmyth/output.h	(working copy)
@@ -13,6 +13,7 @@
 #include <qthread.h>
 #include <qevent.h>
 #include <qptrlist.h>
+#include "mythobservable.h"
 
 class QObject;
 class Buffer;
@@ -21,34 +22,33 @@
 class Visual;
 }
 
-class OutputEvent : public QCustomEvent
+class OutputEvent : public MythEvent
 {
 public:
     enum Type { Playing = (User + 200), Buffering, Info, Paused,
 		Stopped, Error };
 
     OutputEvent(Type t)
-	: QCustomEvent(t), error_msg(0), elasped_seconds(0), written_bytes(0),
+	: MythEvent(t), error_msg(0), elasped_seconds(0), written_bytes(0),
 	  brate(0), freq(0), prec(0), chan(0)
     { ; }
 
     OutputEvent(long s, unsigned long w, int b, int f, int p, int c)
-	: QCustomEvent(Info), error_msg(0), elasped_seconds(s), written_bytes(w),
+	: MythEvent(Info), error_msg(0), elasped_seconds(s), written_bytes(w),
 	  brate(b), freq(f), prec(p), chan(c)
     { ; }
 
     OutputEvent(const QString &e)
-	: QCustomEvent(Error), elasped_seconds(0), written_bytes(0),
+	: MythEvent(Error), elasped_seconds(0), written_bytes(0),
 	  brate(0), freq(0), prec(0), chan(0)
     {
-	error_msg = new QString(e.utf8());
+        error_msg = new QString(e.utf8());
     }
 
 
-    ~OutputEvent()
+    virtual ~OutputEvent()
     {
-	if (error_msg)
-	    delete error_msg;
+        delete error_msg;
     }
 
     const QString *errorMessage() const { return error_msg; }
@@ -60,7 +60,7 @@
     const int &precision() const { return prec; }
     const int &channels() const { return chan; }
 
-
+    virtual OutputEvent *clone() { return new OutputEvent(*this); };
 private:
     QString *error_msg;
 
@@ -70,15 +70,12 @@
 };
 
 
-class OutputListeners
+class OutputListeners : public MythObservable
 {
 public:
     OutputListeners();
     virtual ~OutputListeners();
 
-    void addListener(QObject *);
-    void removeListener(QObject *);
-
     void addVisual(MythTV::Visual *);
     void removeVisual(MythTV::Visual *);
     
@@ -88,7 +85,6 @@
     unsigned int bufferSize() const { return bufsize; }
 
 protected:
-    void dispatch(OutputEvent &e);
     void error(const QString &e);
     void dispatchVisual(uchar *b, unsigned long b_len, 
                        unsigned long written, int chan, int prec);
@@ -96,7 +92,6 @@
 
 private:
     QMutex mtx;
-    QPtrList<QObject> listeners;
     QPtrList<MythTV::Visual> visuals;
     
     unsigned int bufsize;
Index: mythtv/libs/libmyth/mythobservable.cpp
===================================================================
--- mythtv/libs/libmyth/mythobservable.cpp	(revision 0)
+++ mythtv/libs/libmyth/mythobservable.cpp	(revision 0)
@@ -0,0 +1,58 @@
+#include <qobject.h>
+#include <qapplication.h>
+#include "mythobservable.h"
+
+MythObservable::MythObservable()
+{
+}
+
+MythObservable::~MythObservable()
+{
+}
+
+void MythObservable::addListener(QObject *listener)
+{
+    if (m_listeners.find(listener) == -1)
+        m_listeners.append(listener);
+}
+
+void MythObservable::removeListener(QObject *listener)
+{
+    if (m_listeners.find(listener) != -1)
+        m_listeners.remove(listener);
+}
+
+QObject* MythObservable::firstListener()
+{
+    return m_listeners.first();
+}
+
+QObject* MythObservable::nextListener()
+{
+    return m_listeners.next();
+}
+
+QPtrList<QObject> MythObservable::getListeners()
+{
+    return m_listeners;
+}
+
+void MythObservable::dispatch(MythEvent &event)
+{
+    QObject *listener = firstListener();
+    while (listener)
+    {
+        QApplication::postEvent(listener, event.clone());
+        listener = nextListener();
+    }
+}
+
+void MythObservable::dispatchNow(MythEvent &event)
+{
+    QObject *listener = firstListener();
+    while (listener)
+    {
+        QApplication::sendEvent(listener, event.clone());
+        listener = nextListener();
+    }
+}
Index: mythtv/libs/libmyth/mythevent.h
===================================================================
--- mythtv/libs/libmyth/mythevent.h	(revision 0)
+++ mythtv/libs/libmyth/mythevent.h	(revision 0)
@@ -0,0 +1,49 @@
+#ifndef __mythevent_h
+#define __mythevent_h
+
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qevent.h>
+#include <qdeepcopy.h>
+
+/** \class MythEvent
+    \brief This class is used as a container for messages.
+    
+    Any subclass of this that adds data to the event should override
+    the clone method. As example, see OutputEvent in output.h. 
+ */
+class MythEvent : public QCustomEvent
+{
+  public:
+    enum Type { MythEventMessage = (User + 1000) };
+    MythEvent(int t)
+	: QCustomEvent(t)
+	{
+	}
+    MythEvent(const QString lmessage) : QCustomEvent(MythEventMessage)
+    {
+        message = QDeepCopy<QString>(lmessage);
+        extradata = "empty";
+    }
+    MythEvent(const QString lmessage, const QStringList &lextradata)
+           : QCustomEvent(MythEventMessage)
+    {
+        message = QDeepCopy<QString>(lmessage);
+        extradata = lextradata;
+    }
+    
+    virtual ~MythEvent() {}
+
+    const QString& Message() const { return message; }
+    const QString& ExtraData(int idx = 0) const { return extradata[idx]; } 
+    const QStringList& ExtraDataList() const { return extradata; } 
+    int ExtraDataCount() const { return extradata.size(); }
+
+	virtual MythEvent* clone() { return new MythEvent(message, extradata); }
+
+  private:
+    QString message;
+    QStringList extradata;
+};
+
+#endif /* __mythevent_h */
Index: mythtv/libs/libmyth/mythcontext.cpp
===================================================================
--- mythtv/libs/libmyth/mythcontext.cpp	(revision 7868)
+++ mythtv/libs/libmyth/mythcontext.cpp	(working copy)
@@ -112,8 +112,6 @@
 
     QMutex serverSockLock;
 
-    QPtrList<QObject> listeners;
-
     MDBManager m_dbmanager;
     
     QMap<QString, QImage> imageCache;
@@ -2329,38 +2327,6 @@
     d->serverSock = NULL;
 }
 
-void MythContext::addListener(QObject *obj)
-{
-    if (d->listeners.find(obj) == -1)
-        d->listeners.append(obj);
-}
-
-void MythContext::removeListener(QObject *obj)
-{
-    if (d->listeners.find(obj) != -1)
-        d->listeners.remove(obj);
-}
-
-void MythContext::dispatch(MythEvent &e)
-{
-    QObject *obj = d->listeners.first();
-    while (obj)
-    {
-        QApplication::postEvent(obj, new MythEvent(e));
-        obj = d->listeners.next();
-    }
-}
-
-void MythContext::dispatchNow(MythEvent &e)
-{
-    QObject *obj = d->listeners.first();
-    while (obj)
-    {
-        QApplication::sendEvent(obj, &e);
-        obj = d->listeners.next();
-    }
-}
-
 QFont MythContext::GetBigFont(void)
 {
     return QFont("Arial", (int)floor(d->bigfontsize * d->m_hmult), QFont::Bold);
Index: mythtv/libs/libmyth/mythobservable.h
===================================================================
--- mythtv/libs/libmyth/mythobservable.h	(revision 0)
+++ mythtv/libs/libmyth/mythobservable.h	(revision 0)
@@ -0,0 +1,139 @@
+#ifndef __mythobservable_h
+#define __mythobservable_h
+
+#include <qptrlist.h>
+#include "mythevent.h"
+
+class QObject;
+
+/** \class MythObservable
+    \brief Superclass for making an object have a set of listeners
+	
+    This superclass provides the basic API for adding and removing
+    listeners and iterating across them. It is typically used to post
+    events to listening QObjects.
+
+	For example, to post a custom event with event id 100 to all listeners :
+
+	\code
+	void dispatch()
+	{
+	    QObject *listener = firstListener();
+		while (listener) {
+		    QApplication::postEvent (listener, new QCustomEvent(100));
+	        listener = nextListener();  
+	    }
+	}
+	\endcode
+
+    MythEvents can be dispatched to all listeners by calling dispatch
+    or dispatchNow. The former is much preferred as it uses
+    QApplication::postEvent() while the latter uses the blocking
+    QApplication::sendEvent().
+
+	The name MythObservable is 'wrong', since all the methods refer to
+	the observers as listeners (ie. addListener), however,
+	MythListenable just doesn't sound right, and fixing all the calls
+	to addListener was too big a patch.
+*/
+class MythObservable
+{
+public:
+    MythObservable();
+    virtual ~MythObservable();
+	
+    /** \brief Add a listener to the observable 
+
+        Adds the given QObject to the list of objects that observe
+        this observable.
+
+        \param listener the QObject that will listen to this observable
+    */
+    void addListener(QObject *listener);
+
+    /** \brief Remove a listener to the observable 
+
+         Remove the given QObject from the list of objects that
+         observe this observable.
+
+         \param listener the QObject that already listens to this observable
+    */
+    void removeListener(QObject *listener);
+
+    /** \brief Begin iteration across listeners
+
+        If you simply need to iterate across the listeners, use \p
+        firstListener and \p nextListener to iterate across the
+        listeners. Ie. instead of 
+
+        \code
+        {
+            QPtrList<QObject> listeners = getListeners();
+            QObject *listener = listeners.first();
+            while (listener) {
+                // use listener...
+                listener = listeners.next();
+            }
+        }
+        \endcode
+
+        you can avoid the copy and just do
+
+        \code
+        {
+            QObject *listener = firstListener();
+            while (listener) {
+                // use listener...
+                listener = nextListener();
+            }
+        } 
+        \endcode
+
+        \returns pointer to the first listener, NULL if there are no listeners
+    */
+    QObject* firstListener();
+
+    /** \brief Continue iteration to the next listener
+
+        See firstListener. Returns NULL if there are no more listeners.
+
+        \returns pointer to the next listener, NULL if there are no more listeners
+    */
+    QObject* nextListener();
+
+    /** \brief Get a copy of the list of listener
+
+        If you need access to more than just iteration via
+        firstListener/nextListerner, you can call this to obtain a
+        QPtrList with all the listeners.
+
+        \returns a copy of the list of listener
+    */
+    QPtrList<QObject> getListeners(void);
+
+    /** \brief Dispatch an event to all listeners 
+			
+        Makes a copy of the event on the heap by calling
+        MythEvent::clone and dispatches is by calling
+        QApplication::postEvent.
+		
+        \param event a MythEvent to dispatch.
+    */
+    void dispatch(MythEvent &event);
+
+    /** \brief Dispatch an event to all listeners 
+			
+        See dispatch.
+
+        \note This uses QApplication::sendEvent, which is
+        blocking. It's preferred to use dispatch instead.
+
+        \param event a MythEvent to dispatch.
+    */
+    void dispatchNow(MythEvent &event);
+
+private:
+    QPtrList<QObject> m_listeners;
+};
+
+#endif /* __mythobservable_h */
Index: mythplugins/mythmusic/mythmusic/mythmusic.pro
===================================================================
--- mythplugins/mythmusic/mythmusic/mythmusic.pro	(revision 7868)
+++ mythplugins/mythmusic/mythmusic/mythmusic.pro	(working copy)
@@ -35,7 +35,7 @@
 HEADERS += goom/filters.h goom/goomconfig.h goom/goom_core.h goom/graphic.h
 HEADERS += goom/ifs.h goom/lines.h goom/mythgoom.h goom/drawmethods.h
 HEADERS += goom/mmx.h goom/mathtools.h goom/tentacle3d.h goom/v3d.h
-HEADERS += editmetadata.h smartplaylist.h search.h
+HEADERS += editmetadata.h smartplaylist.h search.h genres.h
 
 SOURCES += cddecoder.cpp cdrip.cpp decoder.cpp 
 SOURCES += flacdecoder.cpp flacencoder.cpp maddecoder.cpp main.cpp
@@ -49,4 +49,4 @@
 SOURCES += goom/filters.c goom/goom_core.c goom/graphic.c goom/tentacle3d.c
 SOURCES += goom/ifs.c goom/ifs_display.c goom/lines.c goom/surf3d.c 
 SOURCES += goom/zoom_filter_mmx.c goom/zoom_filter_xmmx.c goom/mythgoom.cpp
-SOURCES += avfdecoder.cpp editmetadata.cpp smartplaylist.cpp search.cpp
+SOURCES += avfdecoder.cpp editmetadata.cpp smartplaylist.cpp search.cpp genres.cpp
Index: mythplugins/mythmusic/mythmusic/decoder.h
===================================================================
--- mythplugins/mythmusic/mythmusic/decoder.h	(revision 7868)
+++ mythplugins/mythmusic/mythmusic/decoder.h	(working copy)
@@ -6,6 +6,7 @@
 #include <qevent.h>
 #include <qthread.h>
 #include <qptrlist.h>
+#include <mythtv/mythobservable.h>
 
 class Metadata;
 class MetaIO;
@@ -21,33 +22,33 @@
 class Recycler;
 class AudioOutput;
 
-class DecoderEvent : public QCustomEvent
+class DecoderEvent : public MythEvent
 {
 public:
     enum Type { Decoding = (QEvent::User + 100), Stopped, Finished, Error };
 
     DecoderEvent(Type t)
-        : QCustomEvent(t), error_msg(0)
+        : MythEvent(t), error_msg(0)
     { ; }
 
     DecoderEvent(QString *e)
-        : QCustomEvent(Error), error_msg(e)
+        : MythEvent(Error), error_msg(e)
     { ; }
 
     ~DecoderEvent()
     {
-        if (error_msg)
-            delete error_msg;
+        delete error_msg;
     }
 
     const QString *errorMessage() const { return error_msg; }
 
+	virtual DecoderEvent *clone();
 
 private:
     QString *error_msg;
 };
 
-class Decoder : public QThread 
+class Decoder : public QThread, public MythObservable
 {
   public:
     virtual ~Decoder();
@@ -58,9 +59,6 @@
 
     DecoderFactory *factory() const { return fctry; }
 
-    void addListener(QObject *);
-    void removeListener(QObject *);
-
     QIODevice *input() { return in; }
     AudioOutput *output() { return out; }
     void setInput(QIODevice *);
@@ -90,8 +88,6 @@
   protected:
     Decoder(DecoderFactory *, QIODevice *, AudioOutput *);
 
-    void dispatch(const DecoderEvent &);
-    void dispatch(const OutputEvent &);
     void error(const QString &);
 
     QString filename;
@@ -103,7 +99,6 @@
   private:
     DecoderFactory *fctry;
 
-    QPtrList<QObject> listeners;
     QIODevice *in;
     AudioOutput *out;
 
Index: mythplugins/mythmusic/mythmusic/genres.c
===================================================================
--- mythplugins/mythmusic/mythmusic/genres.c	(revision 7868)
+++ mythplugins/mythmusic/mythmusic/genres.c	(working copy)
@@ -1,153 +0,0 @@
-const char *genre_table[] =
-{
-	"Blues",
-	"Classic Rock",
-	"Country",
-	"Dance",
-	"Disco",
-	"Funk",
-	"Grunge",
-	"Hip-Hop",
-	"Jazz",
-	"Metal",
-	"New Age",
-	"Oldies",
-	"Other",
-	"Pop",
-	"R&B",
-	"Rap",
-	"Reggae",
-	"Rock",
-	"Techno",
-	"Industrial",
-	"Alternative",
-	"Ska",
-	"Death Metal",
-	"Pranks",
-	"Soundtrack",
-	"Euro-Techno",
-	"Ambient",
-	"Trip-Hop",
-	"Vocal",
-	"Jazz+Funk",
-	"Fusion",
-	"Trance",
-	"Classical",
-	"Instrumental",
-	"Acid",
-	"House",
-	"Game",
-	"Sound Clip",
-	"Gospel",
-	"Noise",
-	"AlternRock",
-	"Bass",
-	"Soul",
-	"Punk",
-	"Space",
-	"Meditative",
-	"Instrumental Pop",
-	"Instrumental Rock",
-	"Ethnic",
-	"Gothic",
-	"Darkwave",
-	"Techno-Industrial",
-	"Electronic",
-	"Pop-Folk",
-	"Eurodance",
-	"Dream",
-	"Southern Rock",
-	"Comedy",
-	"Cult",
-	"Gangsta",
-	"Top 40",
-	"Christian Rap",
-	"Pop/Funk",
-	"Jungle",
-	"Native American",
-	"Cabaret",
-	"New Wave",
-	"Psychedelic",
-	"Rave",
-	"Showtunes",
-	"Trailer",
-	"Lo-Fi",
-	"Tribal",
-	"Acid Punk",
-	"Acid Jazz",
-	"Polka",
-	"Retro",
-	"Musical",
-	"Rock & Roll",
-	"Hard Rock",
-	"Folk",
-	"Folk/Rock",
-	"National Folk",
-	"Swing",
-	"Fast-Fusion",
-	"Bebob",
-	"Latin",
-	"Revival",
-	"Celtic",
-	"Bluegrass",
-	"Avantgarde",
-	"Gothic Rock",
-	"Progressive Rock",
-	"Psychedelic Rock",
-	"Symphonic Rock",
-	"Slow Rock",
-	"Big Band",
-	"Chorus",
-	"Easy Listening",
-	"Acoustic",
-	"Humour",
-	"Speech",
-	"Chanson",
-	"Opera",
-	"Chamber Music",
-	"Sonata",
-	"Symphony",
-	"Booty Bass",
-	"Primus",
-	"Porn Groove",
-	"Satire",
-	"Slow Jam",
-	"Club",
-	"Tango",
-	"Samba",
-	"Folklore",
-	"Ballad",
-	"Power Ballad",
-	"Rhythmic Soul",
-	"Freestyle",
-	"Duet",
-	"Punk Rock",
-	"Drum Solo",
-	"A Cappella",
-	"Euro-House",
-	"Dance Hall",
-	"Goa",
-	"Drum & Bass",
-	"Club-House",
-	"Hardcore",
-	"Terror",
-	"Indie",
-	"BritPop",
-	"Negerpunk",
-	"Polsk Punk",
-	"Beat",
-	"Christian Gangsta Rap",
-	"Heavy Metal",
-	"Black Metal",
-	"Crossover",
-	"Contemporary Christian",
-	"Christian Rock",
-	"Merengue",
-	"Salsa",
-	"Thrash Metal",
-	"Anime",
-	"JPop",
-	"Synthpop"
-};
-
-int genre_table_size = sizeof(genre_table) / sizeof(genre_table[0]);
Index: mythplugins/mythmusic/mythmusic/genres.h
===================================================================
--- mythplugins/mythmusic/mythmusic/genres.h	(revision 0)
+++ mythplugins/mythmusic/mythmusic/genres.h	(revision 0)
@@ -0,0 +1,7 @@
+#ifndef GENRES_H__
+#define GENRES_H__
+
+extern const char *genre_table[];
+extern int genre_table_size;
+
+#endif /* GENRES_H__ */
Index: mythplugins/mythmusic/mythmusic/decoder.cpp
===================================================================
--- mythplugins/mythmusic/mythmusic/decoder.cpp	(revision 7868)
+++ mythplugins/mythmusic/mythmusic/decoder.cpp	(working copy)
@@ -11,6 +11,7 @@
 #include <mythtv/output.h>
 #include <mythtv/visual.h>
 
+#include <qapplication.h>
 #include <qobject.h>
 #include <qptrlist.h>
 #include <qdir.h>
@@ -19,6 +20,16 @@
 
 #include <mythtv/mythcontext.h>
 
+DecoderEvent* DecoderEvent::clone() 
+{ 
+    DecoderEvent *result = new DecoderEvent(*this);
+
+    if (error_msg)
+        result->error_msg = new QString(*error_msg);
+
+    return result;
+}
+
 Decoder::Decoder(DecoderFactory *d, QIODevice *i, AudioOutput *o)
        : fctry(d), in(i), out(o), blksize(0)
 {
@@ -46,49 +57,13 @@
     mutex()->unlock();
 }
 
-void Decoder::dispatch(const DecoderEvent &e)
-{
-    QObject *object = listeners.first();
-    while (object) 
-    {
-        QThread::postEvent(object, new DecoderEvent(e));
-        object = listeners.next();
-    }
-}
-
-void Decoder::dispatch(const OutputEvent &e)
-{
-    QObject *object = listeners.first();
-    while (object) 
-    {
-        QThread::postEvent(object, new OutputEvent(e));
-        object = listeners.next();
-    }
-}
-
 void Decoder::error(const QString &e) 
 {
-    QObject *object = listeners.first();
-    while (object) 
-    {
-        QString *str = new QString(e.utf8());
-        QThread::postEvent(object, new DecoderEvent(str));
-        object = listeners.next();
-    }
+    QString *str = new QString(e.utf8());
+    DecoderEvent ev(str);
+    dispatch(ev);
 }
 
-void Decoder::addListener(QObject *object)
-{
-    if (listeners.find(object) == -1)
-        listeners.append(object);
-}
-
-
-void Decoder::removeListener(QObject *object)
-{
-    listeners.remove(object);
-}
-
 /** \fn Decoder::readMetadata(void)
  *  \brief Read the metadata from \p filename directly.
  *
Index: mythplugins/mythmusic/mythmusic/genres.cpp
===================================================================
--- mythplugins/mythmusic/mythmusic/genres.cpp	(revision 0)
+++ mythplugins/mythmusic/mythmusic/genres.cpp	(revision 0)
@@ -0,0 +1,153 @@
+const char *genre_table[] =
+{
+	"Blues",
+	"Classic Rock",
+	"Country",
+	"Dance",
+	"Disco",
+	"Funk",
+	"Grunge",
+	"Hip-Hop",
+	"Jazz",
+	"Metal",
+	"New Age",
+	"Oldies",
+	"Other",
+	"Pop",
+	"R&B",
+	"Rap",
+	"Reggae",
+	"Rock",
+	"Techno",
+	"Industrial",
+	"Alternative",
+	"Ska",
+	"Death Metal",
+	"Pranks",
+	"Soundtrack",
+	"Euro-Techno",
+	"Ambient",
+	"Trip-Hop",
+	"Vocal",
+	"Jazz+Funk",
+	"Fusion",
+	"Trance",
+	"Classical",
+	"Instrumental",
+	"Acid",
+	"House",
+	"Game",
+	"Sound Clip",
+	"Gospel",
+	"Noise",
+	"AlternRock",
+	"Bass",
+	"Soul",
+	"Punk",
+	"Space",
+	"Meditative",
+	"Instrumental Pop",
+	"Instrumental Rock",
+	"Ethnic",
+	"Gothic",
+	"Darkwave",
+	"Techno-Industrial",
+	"Electronic",
+	"Pop-Folk",
+	"Eurodance",
+	"Dream",
+	"Southern Rock",
+	"Comedy",
+	"Cult",
+	"Gangsta",
+	"Top 40",
+	"Christian Rap",
+	"Pop/Funk",
+	"Jungle",
+	"Native American",
+	"Cabaret",
+	"New Wave",
+	"Psychedelic",
+	"Rave",
+	"Showtunes",
+	"Trailer",
+	"Lo-Fi",
+	"Tribal",
+	"Acid Punk",
+	"Acid Jazz",
+	"Polka",
+	"Retro",
+	"Musical",
+	"Rock & Roll",
+	"Hard Rock",
+	"Folk",
+	"Folk/Rock",
+	"National Folk",
+	"Swing",
+	"Fast-Fusion",
+	"Bebob",
+	"Latin",
+	"Revival",
+	"Celtic",
+	"Bluegrass",
+	"Avantgarde",
+	"Gothic Rock",
+	"Progressive Rock",
+	"Psychedelic Rock",
+	"Symphonic Rock",
+	"Slow Rock",
+	"Big Band",
+	"Chorus",
+	"Easy Listening",
+	"Acoustic",
+	"Humour",
+	"Speech",
+	"Chanson",
+	"Opera",
+	"Chamber Music",
+	"Sonata",
+	"Symphony",
+	"Booty Bass",
+	"Primus",
+	"Porn Groove",
+	"Satire",
+	"Slow Jam",
+	"Club",
+	"Tango",
+	"Samba",
+	"Folklore",
+	"Ballad",
+	"Power Ballad",
+	"Rhythmic Soul",
+	"Freestyle",
+	"Duet",
+	"Punk Rock",
+	"Drum Solo",
+	"A Cappella",
+	"Euro-House",
+	"Dance Hall",
+	"Goa",
+	"Drum & Bass",
+	"Club-House",
+	"Hardcore",
+	"Terror",
+	"Indie",
+	"BritPop",
+	"Negerpunk",
+	"Polsk Punk",
+	"Beat",
+	"Christian Gangsta Rap",
+	"Heavy Metal",
+	"Black Metal",
+	"Crossover",
+	"Contemporary Christian",
+	"Christian Rock",
+	"Merengue",
+	"Salsa",
+	"Thrash Metal",
+	"Anime",
+	"JPop",
+	"Synthpop"
+};
+
+int genre_table_size = sizeof(genre_table) / sizeof(genre_table[0]);
Index: mythplugins/mythmusic/mythmusic/editmetadata.cpp
===================================================================
--- mythplugins/mythmusic/mythmusic/editmetadata.cpp	(revision 7868)
+++ mythplugins/mythmusic/mythmusic/editmetadata.cpp	(working copy)
@@ -3,7 +3,7 @@
 #include <qdir.h>
 #include "editmetadata.h"
 #include "decoder.h"
-#include "genres.c"
+#include "genres.h"
 
 EditMetadataDialog::EditMetadataDialog(Metadata *source_metadata,
                                  MythMainWindow *parent,
