diff --git a/README.txt b/README.txt
index d209ef010051dad78794ad6df5b021b81c8729bb..85e2b24a29f9620b735fa70202c5e67d4387005e 100644
--- a/README.txt
+++ b/README.txt
@@ -12,6 +12,7 @@ Contributors:
     Christian Gavin
     Michael Cristopher Hogg
     Ulrich Leutner
+    Felix Schill
 
 Requirements:
     PyQt 4.7+ or PySide
diff --git a/examples/VideoSpeedTest.py b/examples/VideoSpeedTest.py
index dd392189a6456aabe7773e85332be8293ce8a74c..d7a4e1e0e4c9da7bdedde98b7720468f2ad0773e 100644
--- a/examples/VideoSpeedTest.py
+++ b/examples/VideoSpeedTest.py
@@ -130,8 +130,13 @@ def update():
 
     if ui.rawRadio.isChecked():
         ui.rawImg.setImage(data[ptr%data.shape[0]], lut=useLut, levels=useScale)
+        ui.stack.setCurrentIndex(1)
+    elif ui.rawGLRadio.isChecked():
+        ui.rawGLImg.setImage(data[ptr%data.shape[0]], lut=useLut, levels=useScale)
+        ui.stack.setCurrentIndex(2)
     else:
         img.setImage(data[ptr%data.shape[0]], autoLevels=False, levels=useScale, lut=useLut)
+        ui.stack.setCurrentIndex(0)
         #img.setImage(data[ptr%data.shape[0]], autoRange=False)
         
     ptr += 1
diff --git a/examples/VideoTemplate.ui b/examples/VideoTemplate.ui
index 3dddb9285d20962dd912bf7297fd0e8f1bbc3604..d73b0dc94f2258d0c1716de53528a370dc9a565a 100644
--- a/examples/VideoTemplate.ui
+++ b/examples/VideoTemplate.ui
@@ -6,8 +6,8 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>985</width>
-    <height>674</height>
+    <width>695</width>
+    <height>798</height>
    </rect>
   </property>
   <property name="windowTitle">
@@ -17,33 +17,62 @@
    <layout class="QGridLayout" name="gridLayout_2">
     <item row="1" column="0" colspan="4">
      <layout class="QGridLayout" name="gridLayout">
-      <item row="0" column="0">
-       <widget class="RawImageWidget" name="rawImg" native="true">
-        <property name="sizePolicy">
-         <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
-          <horstretch>0</horstretch>
-          <verstretch>0</verstretch>
-         </sizepolicy>
-        </property>
-       </widget>
-      </item>
-      <item row="0" column="1">
-       <widget class="GraphicsView" name="graphicsView"/>
-      </item>
-      <item row="1" column="0">
+      <item row="3" column="0">
        <widget class="QRadioButton" name="rawRadio">
         <property name="text">
-         <string>RawImageWidget (unscaled; faster)</string>
+         <string>RawImageWidget</string>
         </property>
         <property name="checked">
          <bool>true</bool>
         </property>
        </widget>
       </item>
-      <item row="1" column="1">
+      <item row="2" column="0">
        <widget class="QRadioButton" name="gfxRadio">
         <property name="text">
-         <string>GraphicsView + ImageItem (scaled; slower)</string>
+         <string>GraphicsView + ImageItem</string>
+        </property>
+       </widget>
+      </item>
+      <item row="0" column="0">
+       <widget class="QStackedWidget" name="stack">
+        <property name="currentIndex">
+         <number>2</number>
+        </property>
+        <widget class="QWidget" name="page">
+         <layout class="QGridLayout" name="gridLayout_3">
+          <item row="0" column="0">
+           <widget class="GraphicsView" name="graphicsView"/>
+          </item>
+         </layout>
+        </widget>
+        <widget class="QWidget" name="page_2">
+         <layout class="QGridLayout" name="gridLayout_4">
+          <item row="0" column="0">
+           <widget class="RawImageWidget" name="rawImg" native="true">
+            <property name="sizePolicy">
+             <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+              <horstretch>0</horstretch>
+              <verstretch>0</verstretch>
+             </sizepolicy>
+            </property>
+           </widget>
+          </item>
+         </layout>
+        </widget>
+        <widget class="QWidget" name="page_3">
+         <layout class="QGridLayout" name="gridLayout_5">
+          <item row="0" column="0">
+           <widget class="RawImageGLWidget" name="rawGLImg" native="true"/>
+          </item>
+         </layout>
+        </widget>
+       </widget>
+      </item>
+      <item row="4" column="0">
+       <widget class="QRadioButton" name="rawGLRadio">
+        <property name="text">
+         <string>RawGLImageWidget</string>
         </property>
        </widget>
       </item>
@@ -250,6 +279,12 @@
    <extends>QDoubleSpinBox</extends>
    <header>pyqtgraph</header>
   </customwidget>
+  <customwidget>
+   <class>RawImageGLWidget</class>
+   <extends>QWidget</extends>
+   <header>pyqtgraph.widgets.RawImageWidget</header>
+   <container>1</container>
+  </customwidget>
  </customwidgets>
  <resources/>
  <connections/>
diff --git a/examples/VideoTemplate_pyqt.py b/examples/VideoTemplate_pyqt.py
index c3430e2dc7ae013eb48f841908e0c25f6e34a9de..f61a5e46587fd1eca9aa2275473508ec90bdc233 100644
--- a/examples/VideoTemplate_pyqt.py
+++ b/examples/VideoTemplate_pyqt.py
@@ -1,9 +1,9 @@
 # -*- coding: utf-8 -*-
 
-# Form implementation generated from reading ui file './examples/VideoTemplate.ui'
+# Form implementation generated from reading ui file './VideoTemplate.ui'
 #
-# Created: Sun Nov  4 18:24:20 2012
-#      by: PyQt4 UI code generator 4.9.1
+# Created: Tue Jul  9 23:38:17 2013
+#      by: PyQt4 UI code generator 4.9.3
 #
 # WARNING! All changes made in this file will be lost!
 
@@ -17,31 +17,55 @@ except AttributeError:
 class Ui_MainWindow(object):
     def setupUi(self, MainWindow):
         MainWindow.setObjectName(_fromUtf8("MainWindow"))
-        MainWindow.resize(985, 674)
+        MainWindow.resize(695, 798)
         self.centralwidget = QtGui.QWidget(MainWindow)
         self.centralwidget.setObjectName(_fromUtf8("centralwidget"))
         self.gridLayout_2 = QtGui.QGridLayout(self.centralwidget)
         self.gridLayout_2.setObjectName(_fromUtf8("gridLayout_2"))
         self.gridLayout = QtGui.QGridLayout()
         self.gridLayout.setObjectName(_fromUtf8("gridLayout"))
-        self.rawImg = RawImageWidget(self.centralwidget)
+        self.rawRadio = QtGui.QRadioButton(self.centralwidget)
+        self.rawRadio.setChecked(True)
+        self.rawRadio.setObjectName(_fromUtf8("rawRadio"))
+        self.gridLayout.addWidget(self.rawRadio, 3, 0, 1, 1)
+        self.gfxRadio = QtGui.QRadioButton(self.centralwidget)
+        self.gfxRadio.setObjectName(_fromUtf8("gfxRadio"))
+        self.gridLayout.addWidget(self.gfxRadio, 2, 0, 1, 1)
+        self.stack = QtGui.QStackedWidget(self.centralwidget)
+        self.stack.setObjectName(_fromUtf8("stack"))
+        self.page = QtGui.QWidget()
+        self.page.setObjectName(_fromUtf8("page"))
+        self.gridLayout_3 = QtGui.QGridLayout(self.page)
+        self.gridLayout_3.setObjectName(_fromUtf8("gridLayout_3"))
+        self.graphicsView = GraphicsView(self.page)
+        self.graphicsView.setObjectName(_fromUtf8("graphicsView"))
+        self.gridLayout_3.addWidget(self.graphicsView, 0, 0, 1, 1)
+        self.stack.addWidget(self.page)
+        self.page_2 = QtGui.QWidget()
+        self.page_2.setObjectName(_fromUtf8("page_2"))
+        self.gridLayout_4 = QtGui.QGridLayout(self.page_2)
+        self.gridLayout_4.setObjectName(_fromUtf8("gridLayout_4"))
+        self.rawImg = RawImageWidget(self.page_2)
         sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Preferred)
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
         sizePolicy.setHeightForWidth(self.rawImg.sizePolicy().hasHeightForWidth())
         self.rawImg.setSizePolicy(sizePolicy)
         self.rawImg.setObjectName(_fromUtf8("rawImg"))
-        self.gridLayout.addWidget(self.rawImg, 0, 0, 1, 1)
-        self.graphicsView = GraphicsView(self.centralwidget)
-        self.graphicsView.setObjectName(_fromUtf8("graphicsView"))
-        self.gridLayout.addWidget(self.graphicsView, 0, 1, 1, 1)
-        self.rawRadio = QtGui.QRadioButton(self.centralwidget)
-        self.rawRadio.setChecked(True)
-        self.rawRadio.setObjectName(_fromUtf8("rawRadio"))
-        self.gridLayout.addWidget(self.rawRadio, 1, 0, 1, 1)
-        self.gfxRadio = QtGui.QRadioButton(self.centralwidget)
-        self.gfxRadio.setObjectName(_fromUtf8("gfxRadio"))
-        self.gridLayout.addWidget(self.gfxRadio, 1, 1, 1, 1)
+        self.gridLayout_4.addWidget(self.rawImg, 0, 0, 1, 1)
+        self.stack.addWidget(self.page_2)
+        self.page_3 = QtGui.QWidget()
+        self.page_3.setObjectName(_fromUtf8("page_3"))
+        self.gridLayout_5 = QtGui.QGridLayout(self.page_3)
+        self.gridLayout_5.setObjectName(_fromUtf8("gridLayout_5"))
+        self.rawGLImg = RawImageGLWidget(self.page_3)
+        self.rawGLImg.setObjectName(_fromUtf8("rawGLImg"))
+        self.gridLayout_5.addWidget(self.rawGLImg, 0, 0, 1, 1)
+        self.stack.addWidget(self.page_3)
+        self.gridLayout.addWidget(self.stack, 0, 0, 1, 1)
+        self.rawGLRadio = QtGui.QRadioButton(self.centralwidget)
+        self.rawGLRadio.setObjectName(_fromUtf8("rawGLRadio"))
+        self.gridLayout.addWidget(self.rawGLRadio, 4, 0, 1, 1)
         self.gridLayout_2.addLayout(self.gridLayout, 1, 0, 1, 4)
         self.label = QtGui.QLabel(self.centralwidget)
         self.label.setObjectName(_fromUtf8("label"))
@@ -130,12 +154,14 @@ class Ui_MainWindow(object):
         MainWindow.setCentralWidget(self.centralwidget)
 
         self.retranslateUi(MainWindow)
+        self.stack.setCurrentIndex(2)
         QtCore.QMetaObject.connectSlotsByName(MainWindow)
 
     def retranslateUi(self, MainWindow):
         MainWindow.setWindowTitle(QtGui.QApplication.translate("MainWindow", "MainWindow", None, QtGui.QApplication.UnicodeUTF8))
-        self.rawRadio.setText(QtGui.QApplication.translate("MainWindow", "RawImageWidget (unscaled; faster)", None, QtGui.QApplication.UnicodeUTF8))
-        self.gfxRadio.setText(QtGui.QApplication.translate("MainWindow", "GraphicsView + ImageItem (scaled; slower)", None, QtGui.QApplication.UnicodeUTF8))
+        self.rawRadio.setText(QtGui.QApplication.translate("MainWindow", "RawImageWidget", None, QtGui.QApplication.UnicodeUTF8))
+        self.gfxRadio.setText(QtGui.QApplication.translate("MainWindow", "GraphicsView + ImageItem", None, QtGui.QApplication.UnicodeUTF8))
+        self.rawGLRadio.setText(QtGui.QApplication.translate("MainWindow", "RawGLImageWidget", None, QtGui.QApplication.UnicodeUTF8))
         self.label.setText(QtGui.QApplication.translate("MainWindow", "Data type", None, QtGui.QApplication.UnicodeUTF8))
         self.dtypeCombo.setItemText(0, QtGui.QApplication.translate("MainWindow", "uint8", None, QtGui.QApplication.UnicodeUTF8))
         self.dtypeCombo.setItemText(1, QtGui.QApplication.translate("MainWindow", "uint16", None, QtGui.QApplication.UnicodeUTF8))
@@ -150,4 +176,5 @@ class Ui_MainWindow(object):
         self.fpsLabel.setText(QtGui.QApplication.translate("MainWindow", "FPS", None, QtGui.QApplication.UnicodeUTF8))
         self.rgbCheck.setText(QtGui.QApplication.translate("MainWindow", "RGB", None, QtGui.QApplication.UnicodeUTF8))
 
-from pyqtgraph import SpinBox, GradientWidget, GraphicsView, RawImageWidget
+from pyqtgraph.widgets.RawImageWidget import RawImageGLWidget
+from pyqtgraph import GradientWidget, SpinBox, GraphicsView, RawImageWidget
diff --git a/examples/VideoTemplate_pyside.py b/examples/VideoTemplate_pyside.py
index d19e0f23fd725bfa8f807d5b8979e44968ababed..d0db5effd9851a8ee609774b97ef96d05c8bfeb5 100644
--- a/examples/VideoTemplate_pyside.py
+++ b/examples/VideoTemplate_pyside.py
@@ -1,9 +1,9 @@
 # -*- coding: utf-8 -*-
 
-# Form implementation generated from reading ui file './examples/VideoTemplate.ui'
+# Form implementation generated from reading ui file './VideoTemplate.ui'
 #
-# Created: Sun Nov  4 18:24:21 2012
-#      by: pyside-uic 0.2.13 running on PySide 1.1.0
+# Created: Tue Jul  9 23:38:19 2013
+#      by: pyside-uic 0.2.13 running on PySide 1.1.2
 #
 # WARNING! All changes made in this file will be lost!
 
@@ -12,31 +12,55 @@ from PySide import QtCore, QtGui
 class Ui_MainWindow(object):
     def setupUi(self, MainWindow):
         MainWindow.setObjectName("MainWindow")
-        MainWindow.resize(985, 674)
+        MainWindow.resize(695, 798)
         self.centralwidget = QtGui.QWidget(MainWindow)
         self.centralwidget.setObjectName("centralwidget")
         self.gridLayout_2 = QtGui.QGridLayout(self.centralwidget)
         self.gridLayout_2.setObjectName("gridLayout_2")
         self.gridLayout = QtGui.QGridLayout()
         self.gridLayout.setObjectName("gridLayout")
-        self.rawImg = RawImageWidget(self.centralwidget)
+        self.rawRadio = QtGui.QRadioButton(self.centralwidget)
+        self.rawRadio.setChecked(True)
+        self.rawRadio.setObjectName("rawRadio")
+        self.gridLayout.addWidget(self.rawRadio, 3, 0, 1, 1)
+        self.gfxRadio = QtGui.QRadioButton(self.centralwidget)
+        self.gfxRadio.setObjectName("gfxRadio")
+        self.gridLayout.addWidget(self.gfxRadio, 2, 0, 1, 1)
+        self.stack = QtGui.QStackedWidget(self.centralwidget)
+        self.stack.setObjectName("stack")
+        self.page = QtGui.QWidget()
+        self.page.setObjectName("page")
+        self.gridLayout_3 = QtGui.QGridLayout(self.page)
+        self.gridLayout_3.setObjectName("gridLayout_3")
+        self.graphicsView = GraphicsView(self.page)
+        self.graphicsView.setObjectName("graphicsView")
+        self.gridLayout_3.addWidget(self.graphicsView, 0, 0, 1, 1)
+        self.stack.addWidget(self.page)
+        self.page_2 = QtGui.QWidget()
+        self.page_2.setObjectName("page_2")
+        self.gridLayout_4 = QtGui.QGridLayout(self.page_2)
+        self.gridLayout_4.setObjectName("gridLayout_4")
+        self.rawImg = RawImageWidget(self.page_2)
         sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Preferred)
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
         sizePolicy.setHeightForWidth(self.rawImg.sizePolicy().hasHeightForWidth())
         self.rawImg.setSizePolicy(sizePolicy)
         self.rawImg.setObjectName("rawImg")
-        self.gridLayout.addWidget(self.rawImg, 0, 0, 1, 1)
-        self.graphicsView = GraphicsView(self.centralwidget)
-        self.graphicsView.setObjectName("graphicsView")
-        self.gridLayout.addWidget(self.graphicsView, 0, 1, 1, 1)
-        self.rawRadio = QtGui.QRadioButton(self.centralwidget)
-        self.rawRadio.setChecked(True)
-        self.rawRadio.setObjectName("rawRadio")
-        self.gridLayout.addWidget(self.rawRadio, 1, 0, 1, 1)
-        self.gfxRadio = QtGui.QRadioButton(self.centralwidget)
-        self.gfxRadio.setObjectName("gfxRadio")
-        self.gridLayout.addWidget(self.gfxRadio, 1, 1, 1, 1)
+        self.gridLayout_4.addWidget(self.rawImg, 0, 0, 1, 1)
+        self.stack.addWidget(self.page_2)
+        self.page_3 = QtGui.QWidget()
+        self.page_3.setObjectName("page_3")
+        self.gridLayout_5 = QtGui.QGridLayout(self.page_3)
+        self.gridLayout_5.setObjectName("gridLayout_5")
+        self.rawGLImg = RawImageGLWidget(self.page_3)
+        self.rawGLImg.setObjectName("rawGLImg")
+        self.gridLayout_5.addWidget(self.rawGLImg, 0, 0, 1, 1)
+        self.stack.addWidget(self.page_3)
+        self.gridLayout.addWidget(self.stack, 0, 0, 1, 1)
+        self.rawGLRadio = QtGui.QRadioButton(self.centralwidget)
+        self.rawGLRadio.setObjectName("rawGLRadio")
+        self.gridLayout.addWidget(self.rawGLRadio, 4, 0, 1, 1)
         self.gridLayout_2.addLayout(self.gridLayout, 1, 0, 1, 4)
         self.label = QtGui.QLabel(self.centralwidget)
         self.label.setObjectName("label")
@@ -125,12 +149,14 @@ class Ui_MainWindow(object):
         MainWindow.setCentralWidget(self.centralwidget)
 
         self.retranslateUi(MainWindow)
+        self.stack.setCurrentIndex(2)
         QtCore.QMetaObject.connectSlotsByName(MainWindow)
 
     def retranslateUi(self, MainWindow):
         MainWindow.setWindowTitle(QtGui.QApplication.translate("MainWindow", "MainWindow", None, QtGui.QApplication.UnicodeUTF8))
-        self.rawRadio.setText(QtGui.QApplication.translate("MainWindow", "RawImageWidget (unscaled; faster)", None, QtGui.QApplication.UnicodeUTF8))
-        self.gfxRadio.setText(QtGui.QApplication.translate("MainWindow", "GraphicsView + ImageItem (scaled; slower)", None, QtGui.QApplication.UnicodeUTF8))
+        self.rawRadio.setText(QtGui.QApplication.translate("MainWindow", "RawImageWidget", None, QtGui.QApplication.UnicodeUTF8))
+        self.gfxRadio.setText(QtGui.QApplication.translate("MainWindow", "GraphicsView + ImageItem", None, QtGui.QApplication.UnicodeUTF8))
+        self.rawGLRadio.setText(QtGui.QApplication.translate("MainWindow", "RawGLImageWidget", None, QtGui.QApplication.UnicodeUTF8))
         self.label.setText(QtGui.QApplication.translate("MainWindow", "Data type", None, QtGui.QApplication.UnicodeUTF8))
         self.dtypeCombo.setItemText(0, QtGui.QApplication.translate("MainWindow", "uint8", None, QtGui.QApplication.UnicodeUTF8))
         self.dtypeCombo.setItemText(1, QtGui.QApplication.translate("MainWindow", "uint16", None, QtGui.QApplication.UnicodeUTF8))
@@ -145,4 +171,5 @@ class Ui_MainWindow(object):
         self.fpsLabel.setText(QtGui.QApplication.translate("MainWindow", "FPS", None, QtGui.QApplication.UnicodeUTF8))
         self.rgbCheck.setText(QtGui.QApplication.translate("MainWindow", "RGB", None, QtGui.QApplication.UnicodeUTF8))
 
-from pyqtgraph import SpinBox, GradientWidget, GraphicsView, RawImageWidget
+from pyqtgraph.widgets.RawImageWidget import RawImageGLWidget
+from pyqtgraph import GradientWidget, SpinBox, GraphicsView, RawImageWidget
diff --git a/examples/parametertree.py b/examples/parametertree.py
index 4c5d7275e84d76f367a89e712360f4e8a0d34b72..c0eb50dbff3b69d59d86d2ca4ee08339552d4139 100644
--- a/examples/parametertree.py
+++ b/examples/parametertree.py
@@ -67,7 +67,7 @@ params = [
         {'name': 'Float', 'type': 'float', 'value': 10.5, 'step': 0.1},
         {'name': 'String', 'type': 'str', 'value': "hi"},
         {'name': 'List', 'type': 'list', 'values': [1,2,3], 'value': 2},
-        {'name': 'Named List', 'type': 'list', 'values': {"one": 1, "two": 2, "three": 3}, 'value': 2},
+        {'name': 'Named List', 'type': 'list', 'values': {"one": 1, "two": "twosies", "three": [3,3,3]}, 'value': 2},
         {'name': 'Boolean', 'type': 'bool', 'value': True, 'tip': "This is a checkbox"},
         {'name': 'Color', 'type': 'color', 'value': "FF0", 'tip': "This is a color button"},
         {'name': 'Gradient', 'type': 'colormap'},
@@ -139,14 +139,19 @@ p.param('Save/Restore functionality', 'Restore State').sigActivated.connect(rest
 ## Create two ParameterTree widgets, both accessing the same data
 t = ParameterTree()
 t.setParameters(p, showTop=False)
-t.show()
 t.setWindowTitle('pyqtgraph example: Parameter Tree')
-t.resize(400,800)
 t2 = ParameterTree()
 t2.setParameters(p, showTop=False)
-t2.show()
-t2.resize(400,800)
-    
+
+win = QtGui.QWidget()
+layout = QtGui.QGridLayout()
+win.setLayout(layout)
+layout.addWidget(QtGui.QLabel("These are two views of the same data. They should always display the same values."), 0,  0, 1, 2)
+layout.addWidget(t, 1, 0, 1, 1)
+layout.addWidget(t2, 1, 1, 1, 1)
+win.show()
+win.resize(800,800)
+
 ## test save/restore
 s = p.saveState()
 p.restoreState(s)
diff --git a/pyqtgraph/__init__.py b/pyqtgraph/__init__.py
index d83e0ec001b53725763c7adac4c639d3f4743cba..c1b620419a12100ebbfa9dbd0c79727715de5d44 100644
--- a/pyqtgraph/__init__.py
+++ b/pyqtgraph/__init__.py
@@ -255,7 +255,7 @@ def exit():
     ## close file handles
     os.closerange(3, 4096) ## just guessing on the maximum descriptor count..
     
-    os._exit(os.EX_OK)
+    os._exit(0)
     
 
 
@@ -281,7 +281,7 @@ def plot(*args, **kargs):
     #if len(args)+len(kargs) > 0:
         #w.plot(*args, **kargs)
         
-    pwArgList = ['title', 'labels', 'name', 'left', 'right', 'top', 'bottom']
+    pwArgList = ['title', 'labels', 'name', 'left', 'right', 'top', 'bottom', 'background']
     pwArgs = {}
     dataArgs = {}
     for k in kargs:
diff --git a/pyqtgraph/exporters/Exporter.py b/pyqtgraph/exporters/Exporter.py
index 43a8c33035ce8c604c669737c5e31008d51ccdcd..6371a3b973e712c4cafee423a26d26d5cfcb6e81 100644
--- a/pyqtgraph/exporters/Exporter.py
+++ b/pyqtgraph/exporters/Exporter.py
@@ -119,7 +119,7 @@ class Exporter(object):
         else:
             childs = root.childItems()
             rootItem = [root]
-        childs.sort(lambda a,b: cmp(a.zValue(), b.zValue()))
+        childs.sort(key=lambda a: a.zValue())
         while len(childs) > 0:
             ch = childs.pop(0)
             tree = self.getPaintItems(ch)
diff --git a/pyqtgraph/exporters/ImageExporter.py b/pyqtgraph/exporters/ImageExporter.py
index bdb8b9be184cb63331ab686aad272d8e4f3571d0..a9b44ab441d29a57fd4a5cde2e41862fe5e127f9 100644
--- a/pyqtgraph/exporters/ImageExporter.py
+++ b/pyqtgraph/exporters/ImageExporter.py
@@ -1,6 +1,6 @@
 from .Exporter import Exporter
 from pyqtgraph.parametertree import Parameter
-from pyqtgraph.Qt import QtGui, QtCore, QtSvg
+from pyqtgraph.Qt import QtGui, QtCore, QtSvg, USE_PYSIDE
 import pyqtgraph as pg
 import numpy as np
 
@@ -17,7 +17,11 @@ class ImageExporter(Exporter):
             scene = item.scene()
         else:
             scene = item
-        bg = scene.views()[0].backgroundBrush().color()
+        bgbrush = scene.views()[0].backgroundBrush()
+        bg = bgbrush.color()
+        if bgbrush.style() == QtCore.Qt.NoBrush:
+            bg.setAlpha(0)
+            
         self.params = Parameter(name='params', type='group', children=[
             {'name': 'width', 'type': 'int', 'value': tr.width(), 'limits': (0, None)},
             {'name': 'height', 'type': 'int', 'value': tr.height(), 'limits': (0, None)},
@@ -42,7 +46,10 @@ class ImageExporter(Exporter):
     
     def export(self, fileName=None, toBytes=False, copy=False):
         if fileName is None and not toBytes and not copy:
-            filter = ["*."+str(f) for f in QtGui.QImageWriter.supportedImageFormats()]
+            if USE_PYSIDE:
+                filter = ["*."+str(f) for f in QtGui.QImageWriter.supportedImageFormats()]
+            else:
+                filter = ["*."+bytes(f).decode('utf-8') for f in QtGui.QImageWriter.supportedImageFormats()]
             preferred = ['*.png', '*.tif', '*.jpg']
             for p in preferred[::-1]:
                 if p in filter:
diff --git a/pyqtgraph/flowchart/Flowchart.py b/pyqtgraph/flowchart/Flowchart.py
index be0d86e58b2647482b63ea3d223cd49a5d3803d9..81f9e1637712c356c1af502eb9fde35c62a6dd41 100644
--- a/pyqtgraph/flowchart/Flowchart.py
+++ b/pyqtgraph/flowchart/Flowchart.py
@@ -376,10 +376,10 @@ class Flowchart(Node):
             #tdeps[t] = lastNode
             if lastInd is not None:
                 dels.append((lastInd+1, t))
-        dels.sort(lambda a,b: cmp(b[0], a[0]))
+        #dels.sort(lambda a,b: cmp(b[0], a[0]))
+        dels.sort(key=lambda a: a[0], reverse=True)
         for i, t in dels:
             ops.insert(i, ('d', t))
-            
         return ops
         
         
@@ -491,7 +491,8 @@ class Flowchart(Node):
                 self.clear()
             Node.restoreState(self, state)
             nodes = state['nodes']
-            nodes.sort(lambda a, b: cmp(a['pos'][0], b['pos'][0]))
+            #nodes.sort(lambda a, b: cmp(a['pos'][0], b['pos'][0]))
+            nodes.sort(key=lambda a: a['pos'][0])
             for n in nodes:
                 if n['name'] in self._nodes:
                     #self._nodes[n['name']].graphicsItem().moveBy(*n['pos'])
diff --git a/pyqtgraph/graphicsItems/PlotCurveItem.py b/pyqtgraph/graphicsItems/PlotCurveItem.py
index 881dcf2d333c0114de4aa6c17ccbe111e876997f..742c73ef885dc360fa626a6e4857a0fc8cff9842 100644
--- a/pyqtgraph/graphicsItems/PlotCurveItem.py
+++ b/pyqtgraph/graphicsItems/PlotCurveItem.py
@@ -261,6 +261,9 @@ class PlotCurveItem(GraphicsObject):
                         by :func:`mkBrush <pyqtgraph.mkBrush>` is allowed.
         antialias       (bool) Whether to use antialiasing when drawing. This
                         is disabled by default because it decreases performance.
+        stepMode        If True, two orthogonal lines are drawn for each sample
+                        as steps. This is commonly used when drawing histograms.
+                        Note that in this case, len(x) == len(y) + 1
         ==============  ========================================================
         
         If non-keyword arguments are used, they will be interpreted as
diff --git a/pyqtgraph/graphicsItems/PlotDataItem.py b/pyqtgraph/graphicsItems/PlotDataItem.py
index 1ae528ba2f4609085ca0d6c854a7bcb415c86e7c..f9f2febeb541b00d959160a00dd210d0f662aa4c 100644
--- a/pyqtgraph/graphicsItems/PlotDataItem.py
+++ b/pyqtgraph/graphicsItems/PlotDataItem.py
@@ -475,7 +475,7 @@ class PlotDataItem(GraphicsObject):
         
         if self.xClean is None:
             nanMask = np.isnan(self.xData) | np.isnan(self.yData) | np.isinf(self.xData) | np.isinf(self.yData)
-            if any(nanMask):
+            if nanMask.any():
                 self.dataMask = ~nanMask
                 self.xClean = self.xData[self.dataMask]
                 self.yClean = self.yData[self.dataMask]
@@ -495,10 +495,7 @@ class PlotDataItem(GraphicsObject):
                 ##y = resample(y[:len(x)*ds], len(x))  ## scipy.signal.resample causes nasty ringing
                 #y = y[::ds]
             if self.opts['fftMode']:
-                f = np.fft.fft(y) / len(y)
-                y = abs(f[1:len(f)/2])
-                dt = x[-1] - x[0]
-                x = np.linspace(0, 0.5*len(x)/dt, len(y))
+                x,y = self._fourierTransform(x, y)
             if self.opts['logMode'][0]:
                 x = np.log10(x)
             if self.opts['logMode'][1]:
@@ -666,8 +663,21 @@ class PlotDataItem(GraphicsObject):
             self.xDisp = self.yDisp = None
             self.updateItems()
             
-    
-    
+    def _fourierTransform(self, x, y):
+        ## Perform fourier transform. If x values are not sampled uniformly,
+        ## then use interpolate.griddata to resample before taking fft.
+        dx = np.diff(x)
+        uniform = not np.any(np.abs(dx-dx[0]) > (abs(dx[0]) / 1000.))
+        if not uniform:
+            import scipy.interpolate as interp
+            x2 = np.linspace(x[0], x[-1], len(x))
+            y = interp.griddata(x, y, x2, method='linear')
+            x = x2
+        f = np.fft.fft(y) / len(y)
+        y = abs(f[1:len(f)/2])
+        dt = x[-1] - x[0]
+        x = np.linspace(0, 0.5*len(x)/dt, len(y))
+        return x, y
     
 def dataType(obj):
     if hasattr(obj, '__len__') and len(obj) == 0:
diff --git a/pyqtgraph/graphicsItems/ROI.py b/pyqtgraph/graphicsItems/ROI.py
index a5e25a2f730dbdc3a8fbddf6d2cc5e749dff090d..033aab42a8f1325e3106fc6422c785aa3cdbb15e 100644
--- a/pyqtgraph/graphicsItems/ROI.py
+++ b/pyqtgraph/graphicsItems/ROI.py
@@ -49,7 +49,13 @@ class ROI(GraphicsObject):
     sigRegionChanged        Emitted any time the position of the ROI changes,
                             including while it is being dragged by the user.
     sigHoverEvent           Emitted when the mouse hovers over the ROI.
-    sigClicked              Emitted when the user clicks on the ROI
+    sigClicked              Emitted when the user clicks on the ROI.
+                            Note that clicking is disabled by default to prevent
+                            stealing clicks from objects behind the ROI. To 
+                            enable clicking, call 
+                            roi.setAcceptedMouseButtons(QtCore.Qt.LeftButton). 
+                            See QtGui.QGraphicsItem documentation for more 
+                            details.
     sigRemoveRequested      Emitted when the user selects 'remove' from the 
                             ROI's context menu (if available).
     ----------------------- ----------------------------------------------------
diff --git a/pyqtgraph/graphicsItems/ViewBox/ViewBox.py b/pyqtgraph/graphicsItems/ViewBox/ViewBox.py
index ea04bb16638b8bac8ff925a9115ed96ce8ece03b..7657a6bdc9b2bf2fb25d6554db66715bcb4c53d4 100644
--- a/pyqtgraph/graphicsItems/ViewBox/ViewBox.py
+++ b/pyqtgraph/graphicsItems/ViewBox/ViewBox.py
@@ -139,6 +139,7 @@ class ViewBox(GraphicsWidget):
         self.rbScaleBox = QtGui.QGraphicsRectItem(0, 0, 1, 1)
         self.rbScaleBox.setPen(fn.mkPen((255,255,100), width=1))
         self.rbScaleBox.setBrush(fn.mkBrush(255,255,0,100))
+        self.rbScaleBox.setZValue(1e9)
         self.rbScaleBox.hide()
         self.addItem(self.rbScaleBox, ignoreBounds=True)
         
@@ -792,12 +793,15 @@ class ViewBox(GraphicsWidget):
             else:
                 overlap = min(sg.bottom(), vg.bottom()) - max(sg.top(), vg.top())
                 if overlap < min(vg.height()/3, sg.height()/3):  ## if less than 1/3 of views overlap, 
-                                                               ## then just replicate the view
+                                                                 ## then just replicate the view
                     y1 = vr.top()
                     y2 = vr.bottom()
                 else:  ## views overlap; line them up
                     upp = float(vr.height()) / vg.height()
-                    y2 = vr.bottom() - (sg.y()-vg.y()) * upp
+                    if self.yInverted():
+                        y2 = vr.bottom() + (sg.bottom()-vg.bottom()) * upp
+                    else:
+                        y2 = vr.bottom() + (sg.top()-vg.top()) * upp
                     y1 = y2 - sg.height() * upp
                 self.enableAutoRange(ViewBox.YAxis, False)
                 self.setYRange(y1, y2, padding=0)
diff --git a/pyqtgraph/multiprocess/processes.py b/pyqtgraph/multiprocess/processes.py
index 2b345e8b3cbacb859854d6a7dfb174ced2579048..7d147a1d8629ebec28164150230dff3ed66acf6a 100644
--- a/pyqtgraph/multiprocess/processes.py
+++ b/pyqtgraph/multiprocess/processes.py
@@ -325,7 +325,8 @@ class QtProcess(Process):
       GUI.
     - A QTimer is also started on the parent process which polls for requests
       from the child process. This allows Qt signals emitted within the child 
-      process to invoke slots on the parent process and vice-versa.
+      process to invoke slots on the parent process and vice-versa. This can 
+      be disabled using processRequests=False in the constructor.
       
     Example::
     
@@ -342,18 +343,29 @@ class QtProcess(Process):
     def __init__(self, **kwds):
         if 'target' not in kwds:
             kwds['target'] = startQtEventLoop
+        self._processRequests = kwds.pop('processRequests', True)
         Process.__init__(self, **kwds)
         self.startEventTimer()
         
     def startEventTimer(self):
         from pyqtgraph.Qt import QtGui, QtCore  ## avoid module-level import to keep bootstrap snappy.
         self.timer = QtCore.QTimer()
-        app = QtGui.QApplication.instance()
-        if app is None:
-            raise Exception("Must create QApplication before starting QtProcess")
+        if self._processRequests:
+            app = QtGui.QApplication.instance()
+            if app is None:
+                raise Exception("Must create QApplication before starting QtProcess, or use QtProcess(processRequests=False)")
+            self.startRequestProcessing()
+    
+    def startRequestProcessing(self, interval=0.01):
+        """Start listening for requests coming from the child process.
+        This allows signals to be connected from the child process to the parent.
+        """
         self.timer.timeout.connect(self.processRequests)
-        self.timer.start(10)
+        self.timer.start(interval*1000)
         
+    def stopRequestProcessing(self):
+        self.timer.stop()
+    
     def processRequests(self):
         try:
             Process.processRequests(self)
diff --git a/pyqtgraph/opengl/GLViewWidget.py b/pyqtgraph/opengl/GLViewWidget.py
index 33e9d2fc7e1bf37352c61090ac9ee71eb90caf5b..89fef92ed6a8edc35eccfeb07df8afde0483cb99 100644
--- a/pyqtgraph/opengl/GLViewWidget.py
+++ b/pyqtgraph/opengl/GLViewWidget.py
@@ -167,7 +167,7 @@ class GLViewWidget(QtOpenGL.QGLWidget):
         else:
             items = item.childItems()
             items.append(item)
-        items.sort(key=lambda x: x.depthValue())
+        items.sort(key=lambda a: a.depthValue())
         for i in items:
             if not i.visible():
                 continue
diff --git a/pyqtgraph/opengl/items/GLLinePlotItem.py b/pyqtgraph/opengl/items/GLLinePlotItem.py
index 888af6643d66bd5d125e888b883357d91de7da84..23d227c9dbbe12279b93dc11945ba5059a22b8f6 100644
--- a/pyqtgraph/opengl/items/GLLinePlotItem.py
+++ b/pyqtgraph/opengl/items/GLLinePlotItem.py
@@ -30,8 +30,9 @@ class GLLinePlotItem(GLGraphicsItem):
         Arguments:
         ------------------------------------------------------------------------
         pos                   (N,3) array of floats specifying point locations.
-        color                 tuple of floats (0.0-1.0) specifying
-                              a color for the entire item.
+        color                 (N,4) array of floats (0.0-1.0) or
+                              tuple of floats specifying
+                              a single color for the entire item.
         width                 float specifying line width
         antialias             enables smooth line drawing
         ====================  ==================================================
@@ -71,9 +72,18 @@ class GLLinePlotItem(GLGraphicsItem):
         self.setupGLState()
         
         glEnableClientState(GL_VERTEX_ARRAY)
+
         try:
             glVertexPointerf(self.pos)
-            glColor4f(*self.color)
+            
+            if isinstance(self.color, np.ndarray):
+                glEnableClientState(GL_COLOR_ARRAY)
+                glColorPointerf(self.color)
+            else:
+                if isinstance(self.color, QtGui.QColor):
+                    glColor4f(*fn.glColor(self.color))
+                else:
+                    glColor4f(*self.color)
             glLineWidth(self.width)
             #glPointSize(self.width)
             
@@ -85,6 +95,7 @@ class GLLinePlotItem(GLGraphicsItem):
                 
             glDrawArrays(GL_LINE_STRIP, 0, int(self.pos.size / self.pos.shape[-1]))
         finally:
+            glDisableClientState(GL_COLOR_ARRAY)
             glDisableClientState(GL_VERTEX_ARRAY)
     
         
diff --git a/pyqtgraph/opengl/shaders.py b/pyqtgraph/opengl/shaders.py
index e8ca28d994740713df18c96e3b8fef8e18b3cd9e..515de33a0e4a0edfdea9431bebe7e7931691cae7 100644
--- a/pyqtgraph/opengl/shaders.py
+++ b/pyqtgraph/opengl/shaders.py
@@ -1,3 +1,4 @@
+import OpenGL
 from OpenGL.GL import *
 from OpenGL.GL import shaders
 import re
@@ -218,6 +219,8 @@ class Shader(object):
         if self.compiled is None:
             try:
                 self.compiled = shaders.compileShader(self.code, self.shaderType)
+            except OpenGL.NullFunctionError:
+                raise Exception("This OpenGL implementation does not support shader programs; many features on pyqtgraph will not work.")
             except RuntimeError as exc:
                 ## Format compile errors a bit more nicely
                 if len(exc.args) == 3:
diff --git a/pyqtgraph/parametertree/ParameterTree.py b/pyqtgraph/parametertree/ParameterTree.py
index e57430eaf9497123abc8030a999f04ef040cf188..866875e53642551ba76d6fce250746424472a46b 100644
--- a/pyqtgraph/parametertree/ParameterTree.py
+++ b/pyqtgraph/parametertree/ParameterTree.py
@@ -1,6 +1,7 @@
 from pyqtgraph.Qt import QtCore, QtGui
 from pyqtgraph.widgets.TreeWidget import TreeWidget
 import os, weakref, re
+from .ParameterItem import ParameterItem
 #import functions as fn
         
             
@@ -103,7 +104,7 @@ class ParameterTree(TreeWidget):
         sel = self.selectedItems()
         if len(sel) != 1:
             sel = None
-        if self.lastSel is not None:
+        if self.lastSel is not None and isinstance(self.lastSel, ParameterItem):
             self.lastSel.selected(False)
         if sel is None:
             self.lastSel = None
diff --git a/pyqtgraph/parametertree/parameterTypes.py b/pyqtgraph/parametertree/parameterTypes.py
index 28e1e618cb6c97e902cdd97f59d866e0a72092b0..3300171fcd77d71dd5916ba1f46ee132aa846760 100644
--- a/pyqtgraph/parametertree/parameterTypes.py
+++ b/pyqtgraph/parametertree/parameterTypes.py
@@ -476,32 +476,16 @@ class ListParameterItem(WidgetParameterItem):
         return w
         
     def value(self):
-        #vals = self.param.opts['limits']
         key = asUnicode(self.widget.currentText())
-        #if isinstance(vals, dict):
-            #return vals[key]
-        #else:
-            #return key
-        #print key, self.forward
         
         return self.forward.get(key, None)
             
     def setValue(self, val):
-        #vals = self.param.opts['limits']
-        #if isinstance(vals, dict):
-            #key = None
-            #for k,v in vals.iteritems():
-                #if v == val:
-                    #key = k
-            #if key is None:
-                #raise Exception("Value '%s' not allowed." % val)
-        #else:
-            #key = unicode(val)
         self.targetValue = val
-        if val not in self.reverse:
+        if val not in self.reverse[0]:
             self.widget.setCurrentIndex(0)
         else:
-            key = self.reverse[val]
+            key = self.reverse[1][self.reverse[0].index(val)]
             ind = self.widget.findText(key)
             self.widget.setCurrentIndex(ind)
 
@@ -531,8 +515,8 @@ class ListParameter(Parameter):
     itemClass = ListParameterItem
 
     def __init__(self, **opts):
-        self.forward = OrderedDict()  ## name: value
-        self.reverse = OrderedDict()  ## value: name
+        self.forward = OrderedDict()  ## {name: value, ...}
+        self.reverse = ([], [])       ## ([value, ...], [name, ...])
         
         ## Parameter uses 'limits' option to define the set of allowed values
         if 'values' in opts:
@@ -547,23 +531,40 @@ class ListParameter(Parameter):
         
         Parameter.setLimits(self, limits)
         #print self.name(), self.value(), limits
-        if self.value() not in self.reverse and len(self.reverse) > 0:
-            self.setValue(list(self.reverse.keys())[0])
+        if len(self.reverse) > 0 and self.value() not in self.reverse[0]:
+            self.setValue(self.reverse[0][0])
+            
+    #def addItem(self, name, value=None):
+        #if name in self.forward:
+            #raise Exception("Name '%s' is already in use for this parameter" % name)
+        #limits = self.opts['limits']
+        #if isinstance(limits, dict):
+            #limits = limits.copy()
+            #limits[name] = value
+            #self.setLimits(limits)
+        #else:
+            #if value is not None:
+                #raise Exception  ## raise exception or convert to dict?
+            #limits = limits[:]
+            #limits.append(name)
+        ## what if limits == None?
             
     @staticmethod
     def mapping(limits):
-        ## Return forward and reverse mapping dictionaries given a limit specification
-        forward = OrderedDict()  ## name: value
-        reverse = OrderedDict()  ## value: name
+        ## Return forward and reverse mapping objects given a limit specification
+        forward = OrderedDict()  ## {name: value, ...}
+        reverse = ([], [])       ## ([value, ...], [name, ...])
         if isinstance(limits, dict):
             for k, v in limits.items():
                 forward[k] = v
-                reverse[v] = k
+                reverse[0].append(v)
+                reverse[1].append(k)
         else:
             for v in limits:
                 n = asUnicode(v)
                 forward[n] = v
-                reverse[v] = n
+                reverse[0].append(v)
+                reverse[1].append(n)
         return forward, reverse
 
 registerParameterType('list', ListParameter, override=True)
@@ -615,13 +616,20 @@ registerParameterType('action', ActionParameter, override=True)
 class TextParameterItem(WidgetParameterItem):
     def __init__(self, param, depth):
         WidgetParameterItem.__init__(self, param, depth)
+        self.hideWidget = False
         self.subItem = QtGui.QTreeWidgetItem()
         self.addChild(self.subItem)
 
     def treeWidgetChanged(self):
+        ## TODO: fix so that superclass method can be called
+        ## (WidgetParameter should just natively support this style)
+        #WidgetParameterItem.treeWidgetChanged(self)
         self.treeWidget().setFirstItemColumnSpanned(self.subItem, True)
         self.treeWidget().setItemWidget(self.subItem, 0, self.textBox)
-        self.setExpanded(True)
+        
+        # for now, these are copied from ParameterItem.treeWidgetChanged
+        self.setHidden(not self.param.opts.get('visible', True))
+        self.setExpanded(self.param.opts.get('expanded', True))
         
     def makeWidget(self):
         self.textBox = QtGui.QTextEdit()
diff --git a/pyqtgraph/widgets/GraphicsView.py b/pyqtgraph/widgets/GraphicsView.py
index 6ddfe93033f132767563049048b2809f9a59276b..0c8921f68503415d0cde88f35def173ce6439e7d 100644
--- a/pyqtgraph/widgets/GraphicsView.py
+++ b/pyqtgraph/widgets/GraphicsView.py
@@ -82,6 +82,7 @@ class GraphicsView(QtGui.QGraphicsView):
         ## This might help, but it's probably dangerous in the general case..
         #self.setOptimizationFlag(self.DontSavePainterState, True)
         
+        self.setBackgroundRole(QtGui.QPalette.NoRole)
         self.setBackground(background)
         
         self.setFocusPolicy(QtCore.Qt.StrongFocus)
@@ -138,12 +139,9 @@ class GraphicsView(QtGui.QGraphicsView):
         self._background = background
         if background == 'default':
             background = pyqtgraph.getConfigOption('background')
-        if background is None:
-            self.setBackgroundRole(QtGui.QPalette.NoRole)
-        else:
-            brush = fn.mkBrush(background)
-            self.setBackgroundBrush(brush)
-         
+        brush = fn.mkBrush(background)
+        self.setBackgroundBrush(brush)
+    
     def paintEvent(self, ev):
         self.scene().prepareForPaint()
         #print "GV: paint", ev.rect()
diff --git a/pyqtgraph/widgets/PlotWidget.py b/pyqtgraph/widgets/PlotWidget.py
index 1fa07f2ab4c26fd34ca7cf0229de14cc2b9e0ff9..7b3c685c8ac8406a3884c244834d7388f2c638ea 100644
--- a/pyqtgraph/widgets/PlotWidget.py
+++ b/pyqtgraph/widgets/PlotWidget.py
@@ -40,10 +40,12 @@ class PlotWidget(GraphicsView):
     For all 
     other methods, use :func:`getPlotItem <pyqtgraph.PlotWidget.getPlotItem>`.
     """
-    def __init__(self, parent=None, **kargs):
-        """When initializing PlotWidget, all keyword arguments except *parent* are passed
+    def __init__(self, parent=None, background='default', **kargs):
+        """When initializing PlotWidget, *parent* and *background* are passed to 
+        :func:`GraphicsWidget.__init__() <pyqtgraph.GraphicsWidget.__init__>`
+        and all others are passed
         to :func:`PlotItem.__init__() <pyqtgraph.PlotItem.__init__>`."""
-        GraphicsView.__init__(self, parent)
+        GraphicsView.__init__(self, parent, background=background)
         self.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)
         self.enableMouse(False)
         self.plotItem = PlotItem(**kargs)
diff --git a/pyqtgraph/widgets/RawImageWidget.py b/pyqtgraph/widgets/RawImageWidget.py
index ea5c98a012efdbc3d31f64179c1f508b5135196a..a780f4633780f715b1b43d944d7e7b701d135831 100644
--- a/pyqtgraph/widgets/RawImageWidget.py
+++ b/pyqtgraph/widgets/RawImageWidget.py
@@ -11,8 +11,8 @@ import numpy as np
 class RawImageWidget(QtGui.QWidget):
     """
     Widget optimized for very fast video display. 
-    Generally using an ImageItem inside GraphicsView is fast enough,
-    but if you need even more performance, this widget is about as fast as it gets (but only in unscaled mode).
+    Generally using an ImageItem inside GraphicsView is fast enough.
+    On some systems this may provide faster video. See the VideoSpeedTest example for benchmarking.
     """
     def __init__(self, parent=None, scaled=False):
         """
@@ -59,26 +59,82 @@ class RawImageWidget(QtGui.QWidget):
         p.end()
 
 if HAVE_OPENGL:
+    from OpenGL.GL import *
     class RawImageGLWidget(QtOpenGL.QGLWidget):
         """
         Similar to RawImageWidget, but uses a GL widget to do all drawing.
-        Generally this will be about as fast as using GraphicsView + ImageItem,
-        but performance may vary on some platforms.
+        Perfomance varies between platforms; see examples/VideoSpeedTest for benchmarking.
         """
         def __init__(self, parent=None, scaled=False):
             QtOpenGL.QGLWidget.__init__(self, parent=None)
             self.scaled = scaled
             self.image = None
+            self.uploaded = False
+            self.smooth = False
+            self.opts = None
 
-        def setImage(self, img):
-            self.image = fn.makeQImage(img)
+        def setImage(self, img, *args, **kargs):
+            """
+            img must be ndarray of shape (x,y), (x,y,3), or (x,y,4).
+            Extra arguments are sent to functions.makeARGB
+            """
+            self.opts = (img, args, kargs)
+            self.image = None
+            self.uploaded = False
             self.update()
 
-        def paintEvent(self, ev):
+        def initializeGL(self):
+            self.texture = glGenTextures(1)
+            
+        def uploadTexture(self):
+            glEnable(GL_TEXTURE_2D)
+            glBindTexture(GL_TEXTURE_2D, self.texture)
+            if self.smooth:
+                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
+                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
+            else:
+                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
+                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
+            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER)
+            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER)
+            #glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_BORDER)
+            shape = self.image.shape
+            
+            ### Test texture dimensions first
+            #glTexImage2D(GL_PROXY_TEXTURE_2D, 0, GL_RGBA, shape[0], shape[1], 0, GL_RGBA, GL_UNSIGNED_BYTE, None)
+            #if glGetTexLevelParameteriv(GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH) == 0:
+                #raise Exception("OpenGL failed to create 2D texture (%dx%d); too large for this hardware." % shape[:2])
+            
+            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, shape[0], shape[1], 0, GL_RGBA, GL_UNSIGNED_BYTE, self.image.transpose((1,0,2)))
+            glDisable(GL_TEXTURE_2D)
+            
+        def paintGL(self):
             if self.image is None:
-                return
-            p = QtGui.QPainter(self)
-            p.drawImage(self.rect(), self.image)
-            p.end()
+                if self.opts is None:
+                    return
+                img, args, kwds = self.opts
+                kwds['useRGBA'] = True
+                self.image, alpha = fn.makeARGB(img, *args, **kwds)
+            
+            if not self.uploaded:
+                self.uploadTexture()
+            
+            glViewport(0, 0, self.width(), self.height())
+            glEnable(GL_TEXTURE_2D)
+            glBindTexture(GL_TEXTURE_2D, self.texture)
+            glColor4f(1,1,1,1)
+
+            glBegin(GL_QUADS)
+            glTexCoord2f(0,0)
+            glVertex3f(-1,-1,0)
+            glTexCoord2f(1,0)
+            glVertex3f(1, -1, 0)
+            glTexCoord2f(1,1)
+            glVertex3f(1, 1, 0)
+            glTexCoord2f(0,1)
+            glVertex3f(-1, 1, 0)
+            glEnd()
+            glDisable(GL_TEXTURE_3D)
+