Index: mythmainwindow.cpp
===================================================================
--- mythmainwindow.cpp	(revision 8286)
+++ mythmainwindow.cpp	(working copy)
@@ -29,6 +29,9 @@
 
 //#include "screensaver.h"
 
+#include "mythstroke.h"
+#define GESTURE_TIMEOUT 1000
+
 #ifdef USE_LIRC
 static void *SpawnLirc(void *param)
 {
@@ -127,6 +130,9 @@
 
     bool AllowInput;
 
+    MythStroke stroker;
+    QTimer *strokeTimer;
+
     QRegion repaintRegion;
 };
 
@@ -197,6 +203,8 @@
     d->escapekey = Key_Escape;
     d->mainStack = NULL;
 
+    installEventFilter(this);
+
 #ifdef USE_LIRC
     pthread_t lirc_tid;
     pthread_attr_t attr;
@@ -238,6 +246,9 @@
 
     setAutoBufferSwap(false);
 
+    d->strokeTimer = new QTimer(this);
+    connect(d->strokeTimer, SIGNAL(timeout()), this, SLOT(mouseTimeout()));
+
     d->drawTimer = new QTimer(this);
     connect(d->drawTimer, SIGNAL(timeout()), this, SLOT(drawTimeout()));
     d->drawTimer->start(1000 / 70);
@@ -724,25 +735,128 @@
     d->AllowInput = allow;
 }
 
-void MythMainWindow::keyPressEvent(QKeyEvent *e)
+void MythMainWindow::mouseTimeout()
 {
+    MythGestureEvent *e;
+
+    /* complete the stroke if its our first timeout */
+    if (d->stroker.recording())
+    {
+        d->stroker.stop();
+    }
+
+    /* get the last gesture */
+    e = d->stroker.gesture();
+
+    if (e->gesture() < MythGestureEvent::Click)
+        QApplication::postEvent(this, e);
+}
+
+bool MythMainWindow::eventFilter(QObject *o, QEvent *e)
+{
+
+    MythGestureEvent *ge;
+
+    /* dont let anything through if input is disallowed. */
     if (!d->AllowInput)
-        return;
+        return true;
 
-    QValueVector<MythScreenStack *>::Iterator it;
-    for (it = d->stackList.begin(); it != d->stackList.end(); ++it)
+    /* filter mouse events */
+    switch (e->type())
     {
-         MythScreenType *top = (*it)->GetTopScreen();
-         if (top)
-         {
-             if (top->keyPressEvent(e))
-                 break;
-         }
+    case QEvent::KeyPress:
+
+        QValueVector<MythScreenStack *>::Iterator it;
+        for (it = d->stackList.begin(); it != d->stackList.end(); ++it)
+        {
+            MythScreenType *top = (*it)->GetTopScreen();
+            if (top)
+            {
+                if (top->keyPressEvent(dynamic_cast<QKeyEvent*>(e)))
+                    return true;
+            }
+        }
+        break;
+
+    case QEvent::MouseButtonPress:
+
+        if (!d->stroker.recording())
+        {
+            d->stroker.start();
+            d->stroker.record(dynamic_cast<QMouseEvent*>(e)->pos());
+
+            /* start a single shot timer */
+            d->strokeTimer->start(GESTURE_TIMEOUT);
+
+            return true;
+        }
+
+    case QEvent::MouseButtonRelease:
+
+        if (d->strokeTimer->isActive())
+            d->strokeTimer->stop();
+
+        if (d->stroker.recording())
+        {
+            d->stroker.stop();
+            ge = d->stroker.gesture();
+
+            /* handle clicks separately */
+            if (ge->gesture() == MythGestureEvent::Click)
+            {            
+                MythUIType *clicked;
+                QValueVector<MythScreenStack *>::iterator it;
+                QPoint p = dynamic_cast<QMouseEvent*>(e)->pos();
+
+                delete ge;
+
+                for (it = d->stackList.begin(); it != d->stackList.end(); it++)
+                {
+                    MythScreenType *screen = (*it)->GetTopScreen();
+                    if ((clicked = screen->GetChildAt(p)) != NULL)
+                    {
+                        cout << "UI Type: " << clicked->name() << endl;
+                        break;
+                    }
+                }
+            }
+            else QApplication::postEvent(this, ge);
+
+            return true;
+        }
+
+    case QEvent::MouseMove:
+
+        if (d->stroker.recording())
+        {
+            /* reset the timer */
+            d->strokeTimer->stop();
+            d->strokeTimer->start(GESTURE_TIMEOUT);
+
+            d->stroker.record(dynamic_cast<QMouseEvent*>(e)->pos());
+            return true;
+        }
+
+    default:
+        break;        
     }
+
+    return false;
 }
 
-void MythMainWindow::customEvent(QCustomEvent* /* ce */)
+void MythMainWindow::customEvent(QCustomEvent* ce)
 {
+
+    if (ce->type() == MythGestureEventType)
+    {
+        MythGestureEvent *ge = dynamic_cast<MythGestureEvent*>(ce);
+        if (ge != NULL)
+        {
+            cout << "Gesture: " << QString(*ge) << endl;
+        }
+    }
+
+
 #if 0
     if (ce->type() == kExitToMainMenuEventType && d->exitingtomain)
     {
Index: mythuitype.cpp
===================================================================
--- mythuitype.cpp	(revision 8286)
+++ mythuitype.cpp	(working copy)
@@ -82,6 +82,28 @@
     return &m_ChildrenList;
 }
 
+MythUIType *MythUIType::GetChildAt(const QPoint &p)
+{
+    if (GetArea().contains(p)) {
+
+        /* assumes no selectible ui type will contain another
+         * selectible ui type. */
+        if (CanTakeFocus() && IsVisible()) return this;
+
+        /* check all children */
+        QValueVector<MythUIType*>::iterator it;
+        for (it = m_ChildrenList.begin(); it != m_ChildrenList.end(); ++it)
+        {
+            MythUIType *child = (*it)->GetChildAt(p - GetArea().topLeft());
+            if (child != NULL)
+            {
+                return child;
+            }
+        }
+    }
+    return NULL;
+}
+
 bool MythUIType::NeedsRedraw(void)
 {
     return m_NeedsRedraw;
Index: mythmainwindow.h
===================================================================
--- mythmainwindow.h	(revision 8286)
+++ mythmainwindow.h	(working copy)
@@ -85,11 +85,12 @@
  
   public slots:
     void drawTimeout();
+    void mouseTimeout();
 
   protected:
     MythMainWindow();
 
-    void keyPressEvent(QKeyEvent *e);
+    bool eventFilter(QObject *o, QEvent *e);
     void customEvent(QCustomEvent *ce);
     void closeEvent(QCloseEvent *e);
     void paintEvent(QPaintEvent *e);
Index: libmythui.pro
===================================================================
--- libmythui.pro	(revision 8286)
+++ libmythui.pro	(working copy)
@@ -28,7 +28,7 @@
 SOURCES += mythscreenstack.cpp mythscreentype.cpp 
 SOURCES += mythuitype.cpp mythuiimage.cpp mythuitext.cpp
 SOURCES += mythuistatetype.cpp mythlistbutton.cpp mythfontproperties.cpp
-SOURCES += mythuibutton.cpp themedmenu.cpp dialogbox.cpp
+SOURCES += mythuibutton.cpp themedmenu.cpp dialogbox.cpp mythstroke.cpp
 
 inc.path = $${PREFIX}/include/mythui/
 
@@ -36,7 +36,7 @@
 inc.files += mythpainter_ogl.h mythpainter_qt.h mythuistatetype.h
 inc.files += mythscreenstack.h mythscreentype.h mythuitype.h mythuiimage.h 
 inc.files += mythuitext.h mythuibutton.h mythlistbutton.h
-inc.files += themedmenu.h dialogbox.h mythfontproperties.h
+inc.files += themedmenu.h dialogbox.h mythfontproperties.h mythstroke.h
 
 INSTALLS += inc
 
Index: mythuitype.h
===================================================================
--- mythuitype.h	(revision 8286)
+++ mythuitype.h	(working copy)
@@ -25,6 +25,7 @@
     void AddChild(MythUIType *child);
     MythUIType *GetChild(const char *name, const char *inherits = 0);
     QValueVector<MythUIType *> *GetAllChildren(void);
+    MythUIType *GetChildAt(const QPoint &p);
 
     // Check set dirty status
     bool NeedsRedraw(void);
