diff --git a/AERN-RnToRm-Plot.cabal b/AERN-RnToRm-Plot.cabal
new file mode 100644
--- /dev/null
+++ b/AERN-RnToRm-Plot.cabal
@@ -0,0 +1,46 @@
+Name:           AERN-RnToRm-Plot
+Version:        0.1.0
+Cabal-Version:  >= 1.2
+Build-Type:     Simple
+License:        BSD3
+License-File:   LICENCE
+Author:         Michal Konecny (Aston University)
+Copyright:      (c) 2007-2008 Michal Konecny
+Maintainer:     mik@konecny.aow.cz
+Stability:      experimental
+Category:       Data, Math
+Synopsis:       GL plotting of polynomial function enclosures (PFEs)
+Tested-with:    GHC ==6.8.3
+Description:
+    This library extends AERN-RnToRm with support for plotting unary function enclosures
+    in any GL context and a Gtk window for inspecting these enclosures.
+    .
+    Simple examples of usage can be found in module @Demo.hs@ in folder @tests@.
+Extra-source-files:
+    tests/Demo.hs tests/FnView.glade src/FnView.glade
+Data-files:
+    ChangeLog README.glade
+Flag containers-in-base
+    Default: False
+
+Library
+  hs-source-dirs:  src
+  if flag(containers-in-base)
+    Build-Depends:
+      base < 3, binary >= 0.4, directory, filepath, old-time, stm,
+      AERN-Real >= 0.9.7.1, AERN-RnToRm >= 0.4.1, 
+      OpenGL >= 2.2.1.1, GLUT >= 2.1.1.1,
+      gtk >= 0.9.12.1, gtkglext >= 0.9.12.1, glib >= 0.9.12.1, glade >= 0.9.12.1
+  else
+    Build-Depends:
+      base >= 3, containers, binary >= 0.4, directory, filepath, old-time, stm, 
+      AERN-Real >= 0.9.7.1, AERN-RnToRm >= 0.4.1, 
+      OpenGL >= 2.2.1.1, GLUT >= 2.1.1.1,
+      gtk >= 0.9.12.1, gtkglext >= 0.9.12.1, glib >= 0.9.12.1, glade >= 0.9.12.1
+  Exposed-modules:
+    Data.Number.ER.RnToRm.Plot.FnView,
+    Data.Number.ER.RnToRm.Plot.GLDrawable,
+    Data.Number.ER.RnToRm.Plot.Params,
+    Data.Number.ER.MiscSTM
+    
+  
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,2 @@
+0.1.0: 1 October 2008
+    * initial release of AERN-RnToRm-Plot
diff --git a/LICENCE b/LICENCE
new file mode 100644
--- /dev/null
+++ b/LICENCE
@@ -0,0 +1,30 @@
+Copyright (c) 2007-2008 Michal Konecny
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+3. Neither the name of the author nor the names of his contributors
+   may be used to endorse or promote products derived from this software
+   without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS
+OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
diff --git a/README.glade b/README.glade
new file mode 100644
--- /dev/null
+++ b/README.glade
@@ -0,0 +1,2 @@
+The Gtk window module expects the supplied file FnView.glade 
+to be in $(GLADE_DIR), which defaults to the current directory.
diff --git a/Setup.lhs b/Setup.lhs
new file mode 100644
--- /dev/null
+++ b/Setup.lhs
@@ -0,0 +1,3 @@
+#!/usr/bin/env runhaskell
+> import Distribution.Simple
+> main = defaultMain
diff --git a/src/Data/Number/ER/MiscSTM.hs b/src/Data/Number/ER/MiscSTM.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Number/ER/MiscSTM.hs
@@ -0,0 +1,31 @@
+{-|
+    Utilities related to concurrency.
+-}
+module Data.Number.ER.MiscSTM where
+
+import Control.Concurrent as Concurrent
+import Control.Concurrent.STM as STM
+
+modifyTVar tv update =
+    do
+    value <- readTVar tv
+    writeTVar tv $ update value
+
+modifyTVarGetOldVal tv update =
+    do
+    value <- readTVar tv
+    writeTVar tv $ update value
+    return value
+
+modifyTVarHasChanged tv update =
+    do
+    value <- readTVar tv
+    let newValue = update value
+    if value == newValue
+        then return False
+        else 
+            do
+            writeTVar tv $ update value
+            return True
+    
+    
diff --git a/src/Data/Number/ER/RnToRm/Plot/FnView.hs b/src/Data/Number/ER/RnToRm/Plot/FnView.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Number/ER/RnToRm/Plot/FnView.hs
@@ -0,0 +1,765 @@
+{-# LANGUAGE CPP #-}
+#ifdef GLADE_DIR
+#else
+#define GLADE_DIR "./"
+#endif 
+{-|
+    Module      :  Data.Number.ER.RnToRm.Plot.FAView
+    Description :  plot function enclosures on GL canvas
+    Copyright   :  (c) 2007-2008 Michal Konecny
+    License     :  BSD3
+
+    Maintainer  :  mik@konecny.aow.cz
+    Stability   :  experimental
+    Portability :  portable
+
+    This module provides a generic plotter for a set of function approximations.
+    The functions must be unary at present (R->R^n).
+    
+    To be imported qualified, usually with the synonym FNV.    
+-}
+module Data.Number.ER.RnToRm.Plot.FnView 
+(
+    FaData (..),
+    FnData (..),
+    defaultFaData,
+    defaultFnData,
+    new,
+    module Data.Number.ER.RnToRm.Plot.Params
+)
+where
+
+--import IVPs
+
+import Data.Number.ER.RnToRm.Plot.Params
+import qualified Data.Number.ER.Real.Approx as RA
+import qualified Data.Number.ER.RnToRm.Approx as FA
+import qualified Data.Number.ER.Real.DomainBox as DBox
+import Data.Number.ER.RnToRm.Plot.GLDrawable
+import Data.Number.ER.BasicTypes
+import Data.Number.ER.Misc
+
+import qualified Graphics.UI.Gtk as Gtk
+import Graphics.UI.Gtk (AttrOp((:=)))
+import qualified Graphics.UI.Gtk.Glade as Glade
+import qualified Graphics.UI.Gtk.OpenGL as GtkGL
+import qualified Graphics.UI.GLUT as GLUT
+import qualified System.Glib.Signals as Signals
+
+import qualified Graphics.Rendering.OpenGL as GL
+import Graphics.Rendering.OpenGL (HasSetter(($=)))
+
+import Control.Concurrent as Concurrent
+import Control.Concurrent.STM as STM
+import Data.Number.ER.MiscSTM
+import Data.IORef
+
+import Data.Maybe
+
+import qualified System.FilePath as FilePath
+import System.Directory
+
+{-|
+    Two transactional variables with values of the following two types
+    will be used by the client(s) to communicate to the viewer what it
+    should be showing.
+-}
+data FaData fa =
+    FaData
+    {
+        dataFAs :: [fa] -- ^ functions to plot
+    }
+
+data FnData =
+    FnData
+    {
+        dataDestroyed :: Bool, -- ^ command to destroy OR signal that user destroyed
+        dataFAsUpdated :: Bool, -- ^ avoid checking fas for equality
+        dataDomName :: String, -- ^ name of the domain variable (eg "t")
+        dataDomL :: Double, -- ^ left endpoint of the domain
+        dataDomR :: Double, -- ^ right endpoint of the domain
+        dataValLO :: Double, -- ^ lower bounds for values of all functions
+        dataValHI :: Double, -- ^ upper bounds for values of all functions
+        dataFnNames :: [String],
+        dataResultNames :: [[String]], -- ^ for each function list of result variable names
+        dataDefaultEvalPoint :: Double, -- ^ show the values of the functions at this point
+        dataDefaultEvalPointName :: String, -- ^ label to put on the button
+        dataDefaultPlotParams :: PlotParams
+    }
+    deriving (Eq, Show)
+
+defaultFaData =
+    FaData
+    {
+        dataFAs = []
+    }
+
+defaultFnData =
+    FnData
+    {
+        dataDestroyed = False,
+        dataFAsUpdated = False,
+        dataDomName = "t",
+        dataDomL = 0,
+        dataDomR = 1,
+        dataValLO = 0,
+        dataValHI = 1,
+        dataFnNames = [],
+        dataResultNames = [],
+        dataDefaultEvalPoint = 0,
+        dataDefaultEvalPointName = "default",
+        dataDefaultPlotParams = defaultPlotParams
+    }
+
+readBothTVars :: 
+    (TVar a, TVar a1) -> 
+    STM (a, a1)
+readBothTVars (fadataTV, fndataTV) =
+    do
+    fadata <- readTVar fadataTV
+    fndata <- readTVar fndataTV
+    return (fadata, fndata)
+
+readAll3TVars :: 
+    (TVar a1, TVar a2) -> 
+    TVar a -> 
+    STM ((a1, a2), a)
+readAll3TVars fndataTVs stateTV =
+    do
+    state <- readTVar stateTV
+    fndatas <- readBothTVars fndataTVs 
+    return (fndatas, state)
+
+{-|
+    Create a new viewer linked to the given data variable.
+-}
+new ::
+    (FA.ERFnApprox box varid domra ranra fa, ERFnGLDrawable box varid domra ranra fa) =>
+    (TVar (FaData fa),
+     TVar (FnData)) ->
+    (Maybe Gtk.Window) {- ^ parent window -} -> 
+    IO Gtk.Window
+new fndataTVs@(fadataTV, fndataTV) maybeParentWindow =
+    do
+    -- create initial state objects:
+    stateTV <- atomically $
+        do
+        fadata <- readTVar fadataTV
+        fndata <- readTVar fndataTV
+        STM.newTVar $ initState (fadata, fndata)
+    dynWidgetsRef <- newIORef initERFnViewDynWidgets
+    -- create most widgets:
+    widgets <- loadGlade (FilePath.combine GLADE_DIR "FnView.glade")
+    -- create plotting canvas:
+    widgets <- makeCanvas widgets fndataTVs stateTV
+    -- attach handlers to widgets
+    Gtk.onDestroy (window widgets) $
+        do
+        atomically $ modifyTVar fndataTV $ \fndata -> fndata { dataDestroyed = True }
+        Gtk.mainQuit
+    setHandlers widgets dynWidgetsRef fndataTVs stateTV
+    -- start thread that reponds to changes in fndataTVs:
+    forkIO $ dataWatchThread widgets dynWidgetsRef fndataTVs stateTV
+    Gtk.widgetShowAll $ window widgets
+    return $ window widgets
+
+loadGlade :: 
+    FilePath ->
+    IO Widgets
+loadGlade gladeFileName =
+    do
+    gotGladeFile <- doesFileExist gladeFileName
+    case gotGladeFile of
+        True -> return ()
+        False -> error $ "RnToRm.Plot.FnView: glade file " ++ gladeFileName ++ " not found" 
+    Just xml <- Glade.xmlNew gladeFileName
+    window <- Glade.xmlGetWidget xml Gtk.castToWindow "window1"
+    canvasAlignment <- Glade.xmlGetWidget xml Gtk.castToAlignment "canvasAlignment1"
+    coorSystemCombo <- Glade.xmlGetWidget xml Gtk.castToComboBox "coorSystemCombo1"
+    evalPointEntry <- Glade.xmlGetWidget xml Gtk.castToEntry "evalPointEntry1"
+    defaultEvalPointButton <- Glade.xmlGetWidget xml Gtk.castToButton "defaultEvalPointButton1"
+    dimTable <- Glade.xmlGetWidget xml Gtk.castToTable "dimTable1"
+    domVarLabel <- Glade.xmlGetWidget xml Gtk.castToLabel "domVarLabel1"
+    zoomEntry <- Glade.xmlGetWidget xml Gtk.castToEntry "zoomEntry1"
+    centreXEntry <- Glade.xmlGetWidget xml Gtk.castToEntry "centreXEntry1"
+    centreYEntry <- Glade.xmlGetWidget xml Gtk.castToEntry "centreYEntry1"
+    exportJPGButton <- Glade.xmlGetWidget xml Gtk.castToButton "exportJPGButton1"
+    printTXTButton <- Glade.xmlGetWidget xml Gtk.castToButton "printTXTButton1"
+    return $ Widgets
+        {
+            window = window,
+            canvasAlignment = canvasAlignment,
+            coorSystemCombo = coorSystemCombo,
+            evalPointEntry = evalPointEntry,
+            defaultEvalPointButton = defaultEvalPointButton,
+            dimTable = dimTable,
+            domVarLabel = domVarLabel,
+            zoomEntry = zoomEntry,
+            centreXEntry = centreXEntry,
+            centreYEntry = centreYEntry,
+            exportJPGButton = exportJPGButton,
+            printTXTButton = printTXTButton,
+            canvas = error "canvas not created yet"
+        }
+
+data Widgets = 
+    Widgets
+    {
+        window :: Gtk.Window,
+        canvasAlignment :: Gtk.Alignment,
+        coorSystemCombo :: Gtk.ComboBox,
+        evalPointEntry :: Gtk.Entry,
+        defaultEvalPointButton :: Gtk.Button,
+        dimTable :: Gtk.Table,
+        domVarLabel :: Gtk.Label,
+        zoomEntry :: Gtk.Entry,
+        centreXEntry :: Gtk.Entry,
+        centreYEntry :: Gtk.Entry,
+        exportJPGButton :: Gtk.Button,
+        printTXTButton :: Gtk.Button,
+        canvas :: GtkGL.GLDrawingArea
+    }
+
+data ERFnViewDynWidgets = 
+    ERFnViewDynWidgets
+    {
+        valueLabels :: [[Gtk.Label]]
+    }
+
+initERFnViewDynWidgets :: ERFnViewDynWidgets
+initERFnViewDynWidgets =
+    ERFnViewDynWidgets []    
+    
+data ERFnViewState =
+    ERFnViewState
+    {
+        favstActiveDims :: [[Bool]],
+        favstTrackingDefaultEvalPt :: Bool,
+        favstPlotParams :: PlotParams
+    }
+
+initState :: 
+    (t, FnData) -> 
+    ERFnViewState
+initState (fadata, fndata) =
+    ERFnViewState
+    {
+        favstActiveDims = map (map $ const True) $ dataResultNames fndata,
+        favstTrackingDefaultEvalPt = True,
+        favstPlotParams = dataDefaultPlotParams fndata    
+    }
+    
+updateDimActive :: 
+    TVar ERFnViewState -> 
+    Int -> 
+    Int -> 
+    Bool -> 
+    STM ERFnViewState
+updateDimActive stateTV fnNo dimNo isActive =
+    do
+    modifyTVar stateTV update
+    readTVar stateTV
+    where
+    update state =
+        state
+        {
+            favstActiveDims = updateDim $ favstActiveDims state
+        }
+    updateDim activeDims =
+        listUpdate fnNo activeFnDims activeDims
+        where
+        activeFnDims =
+            listUpdate dimNo isActive (activeDims !! fnNo)
+
+setHandlers :: 
+    (FA.ERFnApprox box varid domra ranra fa, 
+     ERFnGLDrawable box varid domra ranra fa) =>
+    Widgets -> 
+    IORef ERFnViewDynWidgets -> 
+    (TVar (FaData fa), TVar FnData) -> 
+    TVar ERFnViewState -> 
+    IO ()
+setHandlers widgets dynWidgetsRef fndataTVs@(fadataTV, fndataTV) stateTV =
+    do
+    setHandlerPrintTXTButton
+    setHandlerDefaultEvalPointButton
+    setHandlerEvalPointEntry
+    setHandlerCoordSystem
+    return ()
+    where
+    setHandlerCoordSystem =
+        do
+        Gtk.onChanged (coorSystemCombo widgets) $
+            do
+            maybeCSysIx <- Gtk.comboBoxGetActive (coorSystemCombo widgets)
+            case maybeCSysIx of
+                Nothing -> return ()
+                Just ix ->
+                    do
+                    coordSystem <-
+                        atomically $
+                            do
+                            fndata <- readTVar fndataTV
+                            let coordSystem = case ix of
+                                    0 -> CoordSystemLogSqueeze
+                                    1 -> 
+                                        CoordSystemLinear $ Rectangle 
+                                            ((toRational $ dataValHI fndata) + 0.2)
+                                            ((toRational $ dataValLO fndata) - 0.2)
+                                            ((toRational $ dataDomL fndata) - 0.1)
+                                            ((toRational $ dataDomR fndata) + 0.1)
+                            modifyTVar stateTV $ update coordSystem
+                            return coordSystem 
+                    changeCoordSystem coordSystem
+                    where
+                    update coordSystem state =
+                        state 
+                        { 
+                            favstPlotParams = 
+                                (favstPlotParams state) 
+                                    { pltprmCoordSystem = coordSystem } 
+                        } 
+    changeCoordSystem coordSystem =
+        do
+        resetZoom coordSystem
+        (fndatas, state) <- atomically $ readAll3TVars fndataTVs stateTV
+        repaintCanvas (canvas widgets) fndatas state
+        return ()
+        
+    resetZoom CoordSystemLogSqueeze =
+        do
+        Gtk.editableSetEditable (zoomEntry widgets) False
+        Gtk.editableSetEditable (centreXEntry widgets) False
+        Gtk.editableSetEditable (centreYEntry widgets) False
+        Gtk.entrySetText (zoomEntry widgets) ""
+        Gtk.entrySetText (centreXEntry widgets) ""
+        Gtk.entrySetText (centreYEntry widgets) ""
+    resetZoom (CoordSystemLinear (Rectangle hi lo l r)) =
+        do
+--        Gtk.editableSetEditable (zoomEntry widgets) True
+--        Gtk.editableSetEditable (centreXEntry widgets) True
+--        Gtk.editableSetEditable (centreYEntry widgets) True
+        Gtk.editableSetEditable (zoomEntry widgets) False
+        Gtk.editableSetEditable (centreXEntry widgets) False
+        Gtk.editableSetEditable (centreYEntry widgets) False
+        Gtk.entrySetText (zoomEntry widgets) "100"
+        Gtk.entrySetText (centreXEntry widgets) $ show $ (l + r)/2
+        Gtk.entrySetText (centreYEntry widgets) $ show $ (hi + lo)/2
+        
+    setHandlerPrintTXTButton =
+        Gtk.onClicked (printTXTButton widgets) $
+            do
+            (state, FaData fas) <- 
+                atomically $
+                    do
+                    state <- readTVar stateTV
+                    fas <- readTVar fadataTV
+                    return (state, fas)
+            putStrLn $
+--                (show $ head fas)
+--                ++ "\n---------------\n" ++ 
+--                (show $ combustionField 7 $ head fas) 
+                unlines $ map show $ fas
+    setHandlerDefaultEvalPointButton =
+        Gtk.onClicked (defaultEvalPointButton widgets) $
+            do
+            (state, fndata) <- 
+                atomically $
+                    do
+                    state <- readTVar stateTV
+                    fndata <- readTVar fndataTV
+                    return (state, fndata)
+            case favstTrackingDefaultEvalPt state of
+                False ->
+                    do
+                    Gtk.entrySetText (evalPointEntry widgets) $ 
+                        show $ dataDefaultEvalPoint fndata
+                    atomically $ modifyTVar stateTV $
+                        \ st -> st { favstTrackingDefaultEvalPt = True }
+                    updateValueDisplayTV widgets dynWidgetsRef fndataTVs stateTV 
+                True -> -- already tracking the default
+                    return ()
+    setHandlerEvalPointEntry =
+        do
+        Gtk.onEntryActivate (evalPointEntry widgets) $ 
+            do
+            updateEvalPointHandler
+        Gtk.onFocusOut (evalPointEntry widgets) $ \ _ -> 
+            do
+            updateEvalPointHandler
+            return False
+        where
+        updateEvalPointHandler =
+            do
+            -- indicate that we no longer wish to track the default point:  
+            atomically $ modifyTVar stateTV $ 
+                \ st -> st { favstTrackingDefaultEvalPt = False }
+            -- update the values for the new point:  
+            updateValueDisplayTV widgets dynWidgetsRef fndataTVs stateTV
+
+{-|
+    Reconfigure the GUI to show variable names appropriate
+    for the given fndata.
+-}
+updateDimWidgets ::
+    (FA.ERFnApprox box varid domra ranra fa, ERFnGLDrawable box varid domra ranra fa) =>
+    Widgets ->
+    IORef ERFnViewDynWidgets ->
+    FnData ->
+    (TVar (FaData fa),
+     TVar FnData) ->
+    (TVar ERFnViewState) ->
+    IO ()
+updateDimWidgets widgets dynWidgetsRef fndata fndataTVs stateTV =
+    do
+    return ()
+    -- update the name of the domain variable:
+    Gtk.labelSetText (domVarLabel widgets) $ domName ++ "="
+    -- set the default evaluation point:
+    Gtk.entrySetText (evalPointEntry widgets) $ show $ dataDefaultEvalPoint fndata
+    -- remove any old dim rows from dimTable:
+    children <- Gtk.containerGetChildren table
+    mapM (Gtk.containerRemove table) children  
+    -- add new dim rows:
+    Gtk.tableResize table (dimRows + 1) 3
+    -- fill each row with widgets and return all newly created value entries:
+    valueLabels <- addRows [] [] 0 (-1) 0 fnNames ([] : resultNames)
+    -- layout the table:
+    Gtk.widgetShowAll table
+    Gtk.containerResizeChildren table
+    -- remember valueEntries for later use: 
+    modifyIORef dynWidgetsRef $ \ dynWidgets ->
+        dynWidgets
+        {
+            valueLabels = valueLabels
+        } 
+    where
+    table = dimTable widgets
+    domName = dataDomName fndata
+    dimRows = (length fnNames) + (sum $ map length resultNames)
+    fnNames = dataFnNames fndata
+    resultNames = dataResultNames fndata
+    addRows ::
+        [[Gtk.Label]] -> -- accumulator for label groups
+        [Gtk.Label] -> -- accumulator for labels in the current group
+        Int -> -- current table row number
+        Int -> -- current function index
+        Int -> -- current dimension index
+        [String] -> -- function names
+        [[String]] -> -- variable names per result dimension
+        IO ([[Gtk.Label]])
+    addRows prevLabels prevLs nextRowNo fnNo dimNo [] ([]: _) = 
+        return $ tail $ reverse $ prevLs : prevLabels
+    addRows prevLabels prevLs nextRowNo fnNo dimNo (fnName : restFnNames) ([] : resultNames) =
+        do
+        -- add a function label:
+        fnLabel <- Gtk.labelNew (Just fnName)        
+        Gtk.tableAttachDefaults table fnLabel 1 2 nextRowNo nextRowNoPlus1
+        Gtk.set table [ Gtk.tableChildXOptions fnLabel := []]
+        Gtk.miscSetAlignment fnLabel 0 0.5
+        -- continue:
+        addRows newPrevLabels [] nextRowNoPlus1 (fnNo + 1) 0 restFnNames resultNames
+        where
+        nextRowNoPlus1 = nextRowNo + 1
+        newPrevLabels = (reverse prevLs) : prevLabels
+    addRows prevLabels prevLs nextRowNo fnNo dimNo fnNames ((dimName : dimNames) : resultNames) =
+        do
+        -- add variable label:
+        dimLabel <- Gtk.labelNew (Just labelText)
+        Gtk.tableAttachDefaults table dimLabel 1 2 nextRowNo nextRowNoPlus1
+        Gtk.miscSetAlignment dimLabel 0 0.5
+        -- add value label:
+        valLabel <- Gtk.labelNew Nothing
+        Gtk.tableAttachDefaults table valLabel 2 3 nextRowNo nextRowNoPlus1
+        -- add a check button:
+        showCheckButton <- Gtk.checkButtonNew
+        Gtk.tableAttachDefaults table showCheckButton 0 1 nextRowNo nextRowNoPlus1
+        -- make it ticked:
+        Gtk.toggleButtonSetActive showCheckButton True
+        -- give the check button a handler:
+        Gtk.onToggled showCheckButton $
+            do
+            isActive <- Gtk.toggleButtonGetActive showCheckButton
+            state <- atomically $ updateDimActive stateTV fnNo dimNo isActive
+            fndatas <- atomically $ readBothTVars fndataTVs
+            repaintCanvas (canvas widgets) fndatas state
+            return ()
+        -- attempt at a simpler rendering:
+        Gtk.set table 
+            [Gtk.tableChildXOptions dimLabel := [], 
+             Gtk.tableChildXOptions showCheckButton := []]
+        -- continue:
+        addRows prevLabels (valLabel : prevLs) nextRowNoPlus1 fnNo (dimNo + 1) fnNames (dimNames : resultNames)  
+        where
+        labelText = " " ++ dimName ++ "(" ++ domName ++ ")="
+        nextRowNoPlus1 = nextRowNo + 1
+        
+updateView ::
+    (FA.ERFnApprox box varid domra ranra fa, ERFnGLDrawable box varid domra ranra fa) =>
+    Widgets ->
+    IORef ERFnViewDynWidgets ->
+    (ERFnViewState) ->
+    ((FaData fa),
+     FnData) ->
+    IO ()
+updateView widgets dynWidgetsRef state (fadata, fndata) =
+    do
+    updateValueDisplay widgets dynWidgetsRef state (fadata, fndata)
+    repaintCanvas (canvas widgets) (fadata, fndata) state
+    return ()
+
+{-| 
+    update the values shown against variable names
+-}
+updateValueDisplay ::
+    (FA.ERFnApprox box varid domra ranra fa) =>
+    Widgets ->
+    IORef ERFnViewDynWidgets ->
+    (ERFnViewState) ->
+    ((FaData fa),
+     FnData) ->
+    IO ()
+updateValueDisplay widgets dynWidgetsRef state (fadata, fndata) =
+    do
+    evalPointText <- Gtk.entryGetText $ evalPointEntry widgets
+    let maybeFnValueTexts = getFnValueTexts evalPointText 
+    case maybeFnValueTexts of
+        Nothing -> do return () -- putStrLn $ "failed to parse eval point: " ++ evalPointText
+        Just fnValueTexts ->
+            do
+            dynWidgets <- readIORef dynWidgetsRef
+            mapM (mapM $ uncurry Gtk.labelSetText) $ 
+                zipWith zip (valueLabels dynWidgets) fnValueTexts
+            return ()
+    where
+    getFnValueTexts evalPointText =
+        fmap (eval . RA.double2ra) $ readMaybe evalPointText
+        where
+--        eval :: (ERIntApprox ira) => ra -> [[String]] 
+        eval evalPoint =
+            map (map show . getDimValueTexts) $ dataFAs fadata
+            where
+--            getDimValueTexts :: (FA.ERFnApprox box varid domra ranra fa) => fa -> [ra]
+            getDimValueTexts fa = 
+                FA.eval (DBox.unary evalPoint) fa
+
+updateValueDisplayTV widgets dynWidgetsRef fndataTVs stateTV =
+    do
+--    putStrLn "updateValueDisplayTVERFA"
+    (fndatas, state) <- atomically $ readAll3TVars fndataTVs stateTV
+    updateValueDisplay widgets dynWidgetsRef state fndatas    
+             
+dataWatchThread ::
+    (FA.ERFnApprox box varid domra ranra fa, ERFnGLDrawable box varid domra ranra fa) =>
+    Widgets ->
+    IORef ERFnViewDynWidgets ->
+    (TVar (FaData fa),
+     TVar FnData) ->
+    (TVar ERFnViewState) ->
+    IO ()
+dataWatchThread widgets dynWidgetsRef fndataTVs@(fadataTV, fndataTV) stateTV =
+    do
+    fndata <- atomically $ readTVar fndataTV
+    dataWatchLoop fndata
+    where
+    dataWatchLoop fndataOld =
+        do
+        ((dataChange, fndatas@(_, fndata)), state) <- waitForChange fndataOld
+        Gtk.timeoutAdd (do { action dataChange fndatas state; return False }) 10
+        Concurrent.yield
+        case dataChange of
+            DataChangeClose -> return ()
+            _ -> dataWatchLoop fndata
+    action DataChangeClose (fadata, fndata) state =
+        do
+        return ()
+    action DataChangeMeta (fadata, fndata) state =
+        do
+--        putStrLn $ "DataChangeMeta"
+--        putStrLn $ show $ dataFAs fadata
+        updateDimWidgets widgets dynWidgetsRef fndata fndataTVs stateTV
+        let initialisedState = initState (fadata, fndata)
+        atomically $ writeTVar stateTV initialisedState
+        updateView widgets dynWidgetsRef initialisedState (fadata, fndata)
+    action DataChangeFA (fadata, fndata) state =
+        do
+--        putStrLn $ "DataChangeFA"
+--        putStrLn $ show $ dataFAs fadata
+        case favstTrackingDefaultEvalPt state of
+            True -> 
+                Gtk.entrySetText (evalPointEntry widgets) $ 
+                    show $ (dataDefaultEvalPoint fndata)
+            False -> 
+                return () 
+        updateView widgets dynWidgetsRef state (fadata, fndata)
+    action DataChangeDefaultEvalPoint (fadata, fndata) state =
+        do
+--        putStrLn $ "DataChangeDefaultEvalPoint"
+        case favstTrackingDefaultEvalPt state of
+            True ->
+                do
+                Gtk.entrySetText (evalPointEntry widgets) $ 
+                    show $ (dataDefaultEvalPoint fndata) 
+                updateView widgets dynWidgetsRef state (fadata, fndata)
+            False -> return ()
+    waitForChange fndataOld =
+        do
+        waitFC fndataOld
+        where
+        waitFC fndataOld =
+            atomically $
+            do
+            fndata <- readTVar fndataTV
+            (change, fndatas) <- 
+                case fndata == fndataOld of
+                    True -> retry
+                    False ->
+                        case dataFAsUpdated fndata of
+                            True ->
+                                do
+                                fadata <- readTVar fadataTV
+                                let change = returnChange fndataOld fndata fadata
+                                let fndataNew = fndata { dataFAsUpdated = False }
+                                writeTVar fndataTV fndataNew
+                                return (change, (fadata, fndataNew))
+                            False ->
+                                do
+                                let change = returnChange fndataOld fndata undefined
+                                return (change, (undefined, fndata))
+            state <- readTVar stateTV
+            return ((change, fndatas), state) 
+        returnChange fndataOld fndata fadata
+            | dataDestroyed fndata =
+                DataChangeClose
+            | namesChanged = 
+                DataChangeMeta
+            | dataFAsUpdated fndata =
+                DataChangeFA
+            | evalPtChanged =
+                DataChangeDefaultEvalPoint
+            | otherwise =
+                error $ 
+                    "ERFnView: returnChange: cannot detect type of change:\n" 
+                        ++ show fndata ++ "\n" ++ show fndataOld  
+            where
+            changed field = 
+                field fndata /= field fndataOld
+            namesChanged =
+                domNameChanged || resNamesChanged || fnNamesChanged
+            domNameChanged = changed dataDomName
+            resNamesChanged = changed dataResultNames
+            fnNamesChanged = changed dataFnNames 
+            evalPtChanged = changed dataDefaultEvalPoint
+    
+data DataChange 
+    = DataChangeClose -- signals the end...
+    | DataChangeMeta -- all change
+    | DataChangeFA -- only fn & eval point may have changed
+    | DataChangeDefaultEvalPoint -- only eval point has changes
+
+makeCanvas widgets fndataTVs@(fadataTV, fndataTV) stateTV =
+    do
+    -- create canvas:
+    glconfig <- 
+        GtkGL.glConfigNew 
+            [GtkGL.GLModeRGBA,
+             GtkGL.GLModeDepth,
+             GtkGL.GLModeDouble]
+    canvas <- GtkGL.glDrawingAreaNew glconfig
+    -- set canvas properties:
+    Gtk.onRealize canvas $ GtkGL.withGLDrawingArea canvas $ \ _ ->
+        do
+        GL.clearColor $= (GL.Color4 0.05 0.0 0.2 0.0)
+        GL.matrixMode $= GL.Projection
+        GL.loadIdentity
+        GL.ortho 0.0 1.0 0.0 1.0 (-1.0) 1.0
+        GL.depthFunc $= Just GL.Less
+        GL.drawBuffer $= GL.BackBuffers
+    -- set the canvas repaint handler:
+    Gtk.onExpose canvas $ \ event ->
+        do
+        (fndatas, state) <- atomically $
+            do
+            fadata <- readTVar fadataTV
+            fndata <- readTVar fndataTV
+            state <- readTVar stateTV
+            return ((fadata, fndata), state)  
+        repaintCanvas canvas fndatas state
+    -- plug the GL canvas in the GUI:
+    Gtk.set (canvasAlignment widgets)
+        [ Gtk.containerChild := canvas ]
+    return $ widgets { canvas = canvas }
+    
+repaintCanvas ::
+    (FA.ERFnApprox box varid domra ranra fa, ERFnGLDrawable box varid domra ranra fa) =>
+    GtkGL.GLDrawingArea ->
+    ((FaData fa),
+     FnData) ->
+    (ERFnViewState) ->
+    IO Bool    
+repaintCanvas canvas (fadata, fndata) state =
+    do
+    GtkGL.withGLDrawingArea canvas $ \glwindow ->
+        do
+        GL.clear [GL.DepthBuffer, GL.ColorBuffer]
+        drawFG1 $ zip (dataFAs fadata) (favstActiveDims state)
+        drawCoords
+        GtkGL.glDrawableSwapBuffers glwindow
+    return True
+    where
+    plotParams = favstPlotParams state
+    coordSystem = pltprmCoordSystem plotParams
+    drawFG1 [] = return ()
+    drawFG1 ((fa, activeDims) : rest) =
+        do
+        GL.color $ GL.Color3 0.0 0.7 (0.8 :: GL.GLfloat)
+        glDraw (plotParams { pltprmPlotDimensions = activeDims }) fa
+        drawFG2 rest
+    drawFG2 [] = return ()
+    drawFG2 ((fa, activeDims) : rest) =
+        do
+        GL.color $ GL.Color3 0.8 0.4 (0.4 :: GL.GLfloat)
+        glDraw (plotParams { pltprmPlotDimensions = activeDims }) fa
+        drawFG1 rest
+    drawCoords =
+        do
+        GL.color $ GL.Color3 1 0.2 (0.4 :: GL.GLfloat)
+        drawPointLabel 0 0 "0"
+        case pltprmCoordSystem plotParams of
+            CoordSystemLogSqueeze ->
+                do
+                mapM drawXmarks $ [0.1, 0.5, 1, 10, 100]
+                mapM drawYmarks $ [0.1, 0.5, 1, 2, 5, 10, 100, 1000, 1000000, 1000000000000]
+            CoordSystemLinear _ ->
+                do
+                mapM drawXmarks $ [0.25, 0.5, 0.75, 1] -- TODO: use the rectangle
+                mapM drawYmarks $ [0.25, 0.5, 0.75, 1]
+        where
+        drawXmarks xm =
+            do
+            drawPointLabel xm 0 (show xm)
+            drawPointLabel (-xm) 0 (show $ - xm)
+        drawYmarks ym =
+            do
+            drawPointLabel 0 ym (show ym)
+            drawPointLabel 0 (-ym) (show $ - ym)
+        drawPointLabel xModel yModel label =
+            do
+            GL.renderPrimitive GL.Lines $
+                do
+                GL.vertex $ GL.Vertex3 (x - d) y z  
+                GL.vertex $ GL.Vertex3 (x + d) y z
+                GL.vertex $ GL.Vertex3 x (y - d) z
+                GL.vertex $ GL.Vertex3 x (y + d) z
+                GL.vertex $ GL.Vertex3 x y (z - d)
+                GL.vertex $ GL.Vertex3 x y (z + d)
+                drawLabel (x + 2 * d,y - 2 * d,z) label        
+            where
+            d = 0.01 :: GL.GLfloat
+            (x,y) = translateToCoordSystem coordSystem [xModel, yModel]
+            z = 0 
+        drawLabel (x,y,z) label =
+            do
+            GL.rasterPos $ GL.Vertex3 x y z
+            GLUT.renderString GLUT.Fixed9By15 label
+    
diff --git a/src/Data/Number/ER/RnToRm/Plot/GLDrawable.hs b/src/Data/Number/ER/RnToRm/Plot/GLDrawable.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Number/ER/RnToRm/Plot/GLDrawable.hs
@@ -0,0 +1,165 @@
+{-# LANGUAGE MultiParamTypeClasses  #-}
+{-# LANGUAGE FunctionalDependencies #-}
+{-# LANGUAGE UndecidableInstances   #-}
+{-# LANGUAGE FlexibleInstances   #-}
+{-|
+    Module      :  Data.Number.ER.RnToRm.Plot.GLDrawable
+    Description :  plot function enclosures on GL canvas
+    Copyright   :  (c) 2007-2008 Michal Konecny
+    License     :  BSD3
+
+    Maintainer  :  mik@konecny.aow.cz
+    Stability   :  experimental
+    Portability :  portable
+
+    Type class for GL plottable function enclosures,
+    its default implementation, and instance declarations
+    for enclosure types in package AERN-RnToRm. 
+-}
+module Data.Number.ER.RnToRm.Plot.GLDrawable 
+(
+    ERFnGLDrawable(..)
+)
+where
+
+import qualified Data.Number.ER.RnToRm.Approx as FA
+import qualified Data.Number.ER.RnToRm.UnitDom.Approx as UFA
+import qualified Data.Number.ER.Real.Approx as RA
+
+import Data.Number.ER.RnToRm.Approx.DomTransl
+import Data.Number.ER.RnToRm.Approx.DomEdges
+import Data.Number.ER.RnToRm.Approx.Tuple
+import Data.Number.ER.RnToRm.Approx.PieceWise
+
+import qualified Data.Number.ER.RnToRm.BisectionTree as BISTR
+import qualified Data.Number.ER.Real.DomainBox as DBox
+import Data.Number.ER.Real.DomainBox (VariableID(..), DomainBoxMappable, DomainIntBox)
+import Data.Number.ER.RnToRm.Plot.Params
+
+import Data.Number.ER.Misc
+
+import qualified Graphics.Rendering.OpenGL as GL
+
+import qualified Data.Map as Map
+import qualified Data.List as List
+
+class
+    (FA.ERFnDomApprox box varid domra ranra fa) =>
+    ERFnGLDrawable box varid domra ranra fa
+    | fa -> box varid domra ranra 
+    where
+    {-|
+        Plot the function as follows:
+        
+         * @R -> R^n@: draw @n@ 2D graphs in viewport and colours specified by plot params
+          
+         * @R^2 -> R^n@: draw @n@ 3D graphs in viewport and colours specified by plot params
+     -}
+    glDraw :: 
+        PlotParams ->
+        fa -> 
+        IO ()
+    glDraw plotParams f =
+        do
+--        putStrLn $ show partition
+        mapM_ plotEnclosure enclosures
+        return ()
+        where
+        enclosures =
+            map (zip partition) $
+            List.transpose $
+            map pickActiveVals $
+            map (\pt -> FA.eval pt f) $
+            map (DBox.unary) partition
+        partition =
+            [domLO] ++ (map iL [1..(segCnt -1)]) ++ [domHI]
+            where
+            (domLO, domHI) = RA.bounds dom
+            dom = 
+                case DBox.elems $ FA.dom f of
+                    [dom] -> dom
+                    [] -> RA.bottomApprox
+            segCnt = getSegmentCount segPerUnit coordSystem dom
+            segCntRA = fromInteger segCnt
+            iL i =
+                ((segCntRA - iRA) * domLO + iRA * domHI) / segCntRA
+                where
+                iRA = fromInteger i
+        coordSystem = pltprmCoordSystem plotParams
+        segPerUnit = pltprmSegsPerUnit plotParams
+        activeDimensions = pltprmPlotDimensions plotParams
+        pickActiveVals vals =
+            fst $ unzip $ filter snd $ zip vals activeDimensions
+        plotEnclosure :: 
+            (RA.ERIntApprox domra, RA.ERIntApprox ranra) => 
+            [(domra,ranra)] -> 
+            IO ()
+        plotEnclosure interpCoords =
+            do
+            GL.renderPrimitive GL.LineLoop $
+                do
+--                putStrLn $ show interpCoords
+--                putStrLn $ show $ interpCoordsDoubleUpper ++ interpCoordsDoubleLowerReversed
+                mapM_ mkVertexNorm $
+                    interpCoordsDoubleUpper ++ interpCoordsDoubleLowerReversed
+            where
+            interpCoordsDoubleLowerReversed = reverse interpCoordsDoubleLower
+            (interpCoordsDoubleLower, interpCoordsDoubleUpper) = 
+                unzip $ map convertCoords interpCoords
+            convertCoords (d,v) 
+                | RA.isEmpty d =
+                    ((0,0),(0,0))
+                | RA.isEmpty v =
+                    ((dD,0),(dD,0))
+                | otherwise =
+                    ((dD,vD1),(dD,vD2))
+                where
+                (vD1,vD2) = RA.doubleBounds v
+                dD = snd $ RA.doubleBounds d
+        mkVertexNorm (d,v) =
+            do
+            GL.vertex $ GL.Vertex3 dNorm vNorm 0
+            where
+            (dNorm, vNorm) =
+                translateToCoordSystem coordSystem [d, v]
+
+                
+getSegmentCount segPerUnit coordSystem dom 
+    | RA.isEmpty dom = 0
+    | otherwise = 
+--        unsafePrint ("GLDrawable: getSegmentCount: dom = " ++ show dom ++ " domWidthScreen = " ++ show domWidthScreen) $
+        ceiling (segPerUnitRA * domWidthScreen)
+    where
+    segPerUnitRA = fromInteger $ toInteger $ segPerUnit
+    domWidthScreen = min 1 $ domHIScreen - domLOScreen
+    (domLOScreen, _) = 
+        translateToCoordSystem coordSystem [domLO, 0]
+    (domHIScreen, _) = 
+        translateToCoordSystem coordSystem [domHI, 0]
+    (domLO, domHI) = RA.doubleBounds dom
+
+instance 
+    (UFA.ERUnitFnApprox box varid domra ranra ufa,
+     DomainIntBox box varid domra,
+     DomainBoxMappable dtrbox box varid (DomTransl domra) domra, 
+     DomainBoxMappable box dtrbox varid domra (DomTransl domra), 
+     Eq dtrbox) =>
+    ERFnGLDrawable box varid domra ranra (ERFnDomTranslApprox dtrbox varid ufa domra)
+    
+instance
+    (FA.ERFnDomApprox box varid domra ranra fa, 
+     VariableID varid, Show box) =>
+    ERFnGLDrawable box varid domra ranra (ERFnDomEdgesApprox varid fa)
+
+instance
+    (FA.ERFnDomApprox box varid domra ranra fa) =>
+    ERFnGLDrawable box varid domra ranra (ERFnTuple fa)
+    
+instance
+    (ERFnGLDrawable box varid domra ranra fa, RA.ERIntApprox fa, 
+     Show box, DomainBoxMappable box box varid domra domra) =>
+    ERFnGLDrawable box varid domra ranra (ERFnPiecewise box varid domra fa)
+    where
+    glDraw plotParams (ERFnPiecewise bistr) =
+        BISTR.doBistr (\dom -> glDraw plotParams) (Just 15) bistr
+        
diff --git a/src/Data/Number/ER/RnToRm/Plot/Params.hs b/src/Data/Number/ER/RnToRm/Plot/Params.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Number/ER/RnToRm/Plot/Params.hs
@@ -0,0 +1,144 @@
+{-# LANGUAGE DeriveDataTypeable   #-}
+{-|
+    Module      :  Data.Number.ER.RnToRm.Plot.Params
+    Description :  parameters for function plotting
+    Copyright   :  (c) 2007-2008 Michal Konecny
+    License     :  BSD3
+
+    Maintainer  :  mik@konecny.aow.cz
+    Stability   :  experimental
+    Portability :  portable
+
+    Data defining in detail how to plot a function and
+    low-level methods related to plotting.
+-}
+module Data.Number.ER.RnToRm.Plot.Params 
+(
+    PlotParams(..),
+    defaultPlotParams,
+    CoordSystem(..),
+    Rectangle(..),
+    translateToCoordSystem
+)
+where
+
+import Data.Typeable
+import Data.Generics.Basics
+import Data.Binary
+
+data PlotParams =
+    PlotParams
+    {
+        pltprmCoordSystem :: CoordSystem, 
+--        pltprmPlotColours :: [GL.Color4 GL.GLfloat],
+        pltprmPlotDimensions :: [Bool],
+        pltprmSegsPerUnit :: Int
+    }
+    deriving (Eq, Show, Typeable, Data)
+  
+{- the following has been generated by BinaryDerive -}     
+instance Binary PlotParams where
+  put (PlotParams a b c) = put a >> put b >> put c
+  get = get >>= \a -> get >>= \b -> get >>= \c -> return (PlotParams a b c)
+{- the above has been generated by BinaryDerive -}
+  
+
+data CoordSystem 
+    = CoordSystemLinear Rectangle
+    | CoordSystemLog Rectangle
+    | CoordSystemSqueeze
+    | CoordSystemLogSqueeze
+    deriving (Eq, Ord, Show, Typeable, Data)
+
+data Rectangle =
+    Rectangle 
+    {
+        rectTop :: Rational,
+        rectBottom :: Rational,
+        rectLeft :: Rational,
+        rectRight :: Rational
+    }
+    deriving (Eq, Ord, Show, Typeable, Data)
+    
+    
+{- the following has been generated by BinaryDerive -}
+instance Binary CoordSystem where
+  put (CoordSystemLinear a) = putWord8 0 >> put a
+  put (CoordSystemLog a) = putWord8 1 >> put a
+  put CoordSystemSqueeze = putWord8 2
+  put CoordSystemLogSqueeze = putWord8 3
+  get = do
+    tag_ <- getWord8
+    case tag_ of
+      0 -> get >>= \a -> return (CoordSystemLinear a)
+      1 -> get >>= \a -> return (CoordSystemLog a)
+      2 -> return CoordSystemSqueeze
+      3 -> return CoordSystemLogSqueeze
+      _ -> fail "no parse"
+instance Binary Rectangle where
+  put (Rectangle a b c d) = put a >> put b >> put c >> put d
+  get = get >>= \a -> get >>= \b -> get >>= \c -> get >>= \d -> return (Rectangle a b c d)
+{- the above has been generated by BinaryDerive -}
+
+    
+defaultPlotParams =
+    PlotParams
+    {
+        pltprmCoordSystem = CoordSystemLogSqueeze,
+--        pltprmPlotColours = [GL.Color4 1 0.2 (0.4 :: GL.GLfloat) 1],
+        pltprmPlotDimensions = replicate 4 True,
+        pltprmSegsPerUnit = 100
+    }
+    
+{-|
+    Translate a point given by a number of coordinates to
+    a 2D point assuming that only result points in the rectangle
+    (0,0) --- (1,1) are visible, the origin being at the top left.
+-}
+translateToCoordSystem ::
+    (Floating ra, Ord ra) =>
+    CoordSystem ->
+    [ra] ->
+    (ra, ra)
+translateToCoordSystem csys pt =
+    case (csys, pt) of
+        (CoordSystemLogSqueeze, [x,y]) ->
+            (logSqueeze 0.5 x, logSqueeze 0.5 y)
+        (CoordSystemLinear (Rectangle t b l r), [x,y]) ->
+            (linTransViaRat l r x, 
+             linTransViaRat b t y)
+
+linTransViaRat r0 r1 x =
+    linTransform (fromRational r0) (fromRational r1) x 
+
+linTransform x0 x1 x =
+    (x - x0) / (x1 - x0)
+
+logSqueeze v1 =
+    (\x -> (x + 1) /2) . (normalise v1) . logScale
+    
+{-|
+    Convert a number from range [-oo,+oo] to
+    range (-1,1), mapping 1 to v1.
+-}
+normalise :: 
+    (Fractional a, Ord a) => 
+    a {-^ v1 -} -> 
+    a {-^ x -} -> 
+    a
+normalise v1 x 
+    | v1ok && x < 0 = - 1 + a/(a - x)
+    | v1ok = 1 - a/(a + x)
+    where
+    v1ok = 0 < v1 && v1 < 1
+    a = (1 - v1) / v1
+    
+{-|
+    Map the range [-oo,oo] to itself with a logarithmic scale.
+-}
+logScale :: (Floating a, Ord a) => a -> a
+logScale x
+    | x < 0 = - (logScale (-x))
+    | otherwise = log (x + 1)
+
+    
diff --git a/src/FnView.glade b/src/FnView.glade
new file mode 100644
--- /dev/null
+++ b/src/FnView.glade
@@ -0,0 +1,466 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
+<!--Generated with glade3 3.4.5 on Wed Oct  1 15:09:10 2008 -->
+<glade-interface>
+  <widget class="GtkWindow" id="window1">
+    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+    <child>
+      <widget class="GtkHBox" id="hbox1">
+        <property name="visible">True</property>
+        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+        <child>
+          <widget class="GtkVBox" id="vbox1">
+            <property name="visible">True</property>
+            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+            <child>
+              <widget class="GtkFrame" id="frame1">
+                <property name="visible">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="label_xalign">0</property>
+                <property name="shadow_type">GTK_SHADOW_ETCHED_OUT</property>
+                <child>
+                  <widget class="GtkAlignment" id="canvasAlignment1">
+                    <property name="width_request">500</property>
+                    <property name="height_request">500</property>
+                    <property name="visible">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="left_padding">12</property>
+                    <child>
+                      <placeholder/>
+                    </child>
+                  </widget>
+                </child>
+                <child>
+                  <widget class="GtkLabel" id="label1">
+                    <property name="visible">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="label" translatable="yes">plot</property>
+                  </widget>
+                  <packing>
+                    <property name="type">label_item</property>
+                  </packing>
+                </child>
+              </widget>
+            </child>
+            <child>
+              <widget class="GtkHBox" id="hbox2">
+                <property name="visible">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <child>
+                  <widget class="GtkFrame" id="frame2">
+                    <property name="visible">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="label_xalign">0</property>
+                    <property name="shadow_type">GTK_SHADOW_ETCHED_OUT</property>
+                    <child>
+                      <widget class="GtkAlignment" id="alignment2">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="left_padding">12</property>
+                        <child>
+                          <widget class="GtkVBox" id="vbox3">
+                            <property name="visible">True</property>
+                            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                            <child>
+                              <widget class="GtkComboBox" id="coorSystemCombo1">
+                                <property name="visible">True</property>
+                                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                                <property name="items" translatable="yes">log + squeeze
+linear</property>
+                              </widget>
+                            </child>
+                            <child>
+                              <widget class="GtkHBox" id="hbox6">
+                                <property name="visible">True</property>
+                                <child>
+                                  <placeholder/>
+                                </child>
+                              </widget>
+                              <packing>
+                                <property name="position">1</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <widget class="GtkHBox" id="hbox7">
+                                <property name="visible">True</property>
+                                <child>
+                                  <placeholder/>
+                                </child>
+                              </widget>
+                              <packing>
+                                <property name="position">2</property>
+                              </packing>
+                            </child>
+                          </widget>
+                        </child>
+                      </widget>
+                    </child>
+                    <child>
+                      <widget class="GtkLabel" id="label2">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="label" translatable="yes">coord system</property>
+                        <property name="use_markup">True</property>
+                      </widget>
+                      <packing>
+                        <property name="type">label_item</property>
+                      </packing>
+                    </child>
+                  </widget>
+                </child>
+                <child>
+                  <widget class="GtkFrame" id="frame3">
+                    <property name="visible">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="label_xalign">0</property>
+                    <property name="shadow_type">GTK_SHADOW_ETCHED_OUT</property>
+                    <child>
+                      <widget class="GtkAlignment" id="alignment3">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="left_padding">12</property>
+                        <child>
+                          <widget class="GtkTable" id="table2">
+                            <property name="visible">True</property>
+                            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                            <property name="n_rows">4</property>
+                            <property name="n_columns">1</property>
+                            <child>
+                              <placeholder/>
+                            </child>
+                            <child>
+                              <widget class="GtkButton" id="defaultZoomPanButton1">
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="receives_default">True</property>
+                                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                                <property name="label" translatable="yes">set to defaults</property>
+                                <property name="response_id">0</property>
+                              </widget>
+                              <packing>
+                                <property name="y_options">GTK_FILL</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <widget class="GtkHBox" id="hbox4">
+                                <property name="visible">True</property>
+                                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                                <child>
+                                  <widget class="GtkLabel" id="label6">
+                                    <property name="visible">True</property>
+                                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                                    <property name="xalign">0</property>
+                                    <property name="label" translatable="yes">zoom=</property>
+                                  </widget>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <widget class="GtkEntry" id="zoomEntry1">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                                    <property name="width_chars">5</property>
+                                    <property name="truncate_multiline">True</property>
+                                  </widget>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="fill">False</property>
+                                    <property name="position">1</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <widget class="GtkLabel" id="label7">
+                                    <property name="visible">True</property>
+                                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                                    <property name="label" translatable="yes">%</property>
+                                  </widget>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="position">2</property>
+                                  </packing>
+                                </child>
+                              </widget>
+                              <packing>
+                                <property name="top_attach">1</property>
+                                <property name="bottom_attach">2</property>
+                                <property name="y_options">GTK_FILL</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <widget class="GtkTable" id="table3">
+                                <property name="visible">True</property>
+                                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                                <property name="n_rows">2</property>
+                                <property name="n_columns">3</property>
+                                <child>
+                                  <placeholder/>
+                                </child>
+                                <child>
+                                  <placeholder/>
+                                </child>
+                                <child>
+                                  <widget class="GtkLabel" id="label8">
+                                    <property name="visible">True</property>
+                                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                                    <property name="xalign">0</property>
+                                    <property name="label" translatable="yes">centre x=</property>
+                                  </widget>
+                                  <packing>
+                                    <property name="x_options">GTK_FILL</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <widget class="GtkLabel" id="label9">
+                                    <property name="visible">True</property>
+                                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                                    <property name="xalign">0</property>
+                                    <property name="label" translatable="yes">centre y=</property>
+                                  </widget>
+                                  <packing>
+                                    <property name="top_attach">1</property>
+                                    <property name="bottom_attach">2</property>
+                                    <property name="x_options">GTK_FILL</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <widget class="GtkEntry" id="centreXEntry1">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                                    <property name="width_chars">5</property>
+                                  </widget>
+                                  <packing>
+                                    <property name="left_attach">1</property>
+                                    <property name="right_attach">2</property>
+                                    <property name="x_options">GTK_FILL</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <widget class="GtkEntry" id="centreYEntry1">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                                    <property name="width_chars">5</property>
+                                  </widget>
+                                  <packing>
+                                    <property name="left_attach">1</property>
+                                    <property name="right_attach">2</property>
+                                    <property name="top_attach">1</property>
+                                    <property name="bottom_attach">2</property>
+                                    <property name="x_options">GTK_FILL</property>
+                                  </packing>
+                                </child>
+                              </widget>
+                              <packing>
+                                <property name="top_attach">2</property>
+                                <property name="bottom_attach">3</property>
+                                <property name="y_options">GTK_FILL</property>
+                              </packing>
+                            </child>
+                          </widget>
+                        </child>
+                      </widget>
+                    </child>
+                    <child>
+                      <widget class="GtkLabel" id="label3">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="label" translatable="yes">zoom/pan</property>
+                        <property name="use_markup">True</property>
+                      </widget>
+                      <packing>
+                        <property name="type">label_item</property>
+                      </packing>
+                    </child>
+                  </widget>
+                  <packing>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </widget>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </widget>
+        </child>
+        <child>
+          <widget class="GtkVBox" id="vbox2">
+            <property name="visible">True</property>
+            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+            <child>
+              <widget class="GtkHBox" id="hbox5">
+                <property name="visible">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <child>
+                  <widget class="GtkButton" id="defaultEvalPointButton1">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="label" translatable="yes">default</property>
+                    <property name="response_id">0</property>
+                  </widget>
+                </child>
+                <child>
+                  <widget class="GtkLabel" id="domVarLabel1">
+                    <property name="visible">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="label" translatable="yes">==</property>
+                  </widget>
+                  <packing>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="GtkEntry" id="evalPointEntry1">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                  </widget>
+                  <packing>
+                    <property name="position">2</property>
+                  </packing>
+                </child>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+                <property name="padding">2</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkTable" id="dimTable1">
+                <property name="visible">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="resize_mode">GTK_RESIZE_IMMEDIATE</property>
+                <property name="n_rows">4</property>
+                <property name="n_columns">3</property>
+                <property name="column_spacing">1</property>
+                <property name="row_spacing">5</property>
+                <child>
+                  <placeholder/>
+                </child>
+                <child>
+                  <placeholder/>
+                </child>
+                <child>
+                  <placeholder/>
+                </child>
+                <child>
+                  <placeholder/>
+                </child>
+                <child>
+                  <placeholder/>
+                </child>
+                <child>
+                  <placeholder/>
+                </child>
+                <child>
+                  <placeholder/>
+                </child>
+                <child>
+                  <placeholder/>
+                </child>
+                <child>
+                  <placeholder/>
+                </child>
+                <child>
+                  <placeholder/>
+                </child>
+                <child>
+                  <placeholder/>
+                </child>
+                <child>
+                  <placeholder/>
+                </child>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+                <property name="padding">2</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+            <child>
+              <placeholder/>
+            </child>
+            <child>
+              <widget class="GtkFrame" id="frame4">
+                <property name="visible">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="label_xalign">0</property>
+                <property name="shadow_type">GTK_SHADOW_ETCHED_OUT</property>
+                <child>
+                  <widget class="GtkAlignment" id="alignment1">
+                    <property name="visible">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="left_padding">12</property>
+                    <child>
+                      <widget class="GtkHBox" id="hbox3">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <child>
+                          <widget class="GtkButton" id="exportJPGButton1">
+                            <property name="can_focus">True</property>
+                            <property name="receives_default">True</property>
+                            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                            <property name="label" translatable="yes">jpg</property>
+                            <property name="response_id">0</property>
+                          </widget>
+                        </child>
+                        <child>
+                          <widget class="GtkButton" id="printTXTButton1">
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="receives_default">True</property>
+                            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                            <property name="label" translatable="yes">txt</property>
+                            <property name="response_id">0</property>
+                          </widget>
+                          <packing>
+                            <property name="position">1</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <widget class="GtkVBox" id="vbox4">
+                            <property name="visible">True</property>
+                            <child>
+                              <placeholder/>
+                            </child>
+                          </widget>
+                          <packing>
+                            <property name="position">2</property>
+                          </packing>
+                        </child>
+                      </widget>
+                    </child>
+                  </widget>
+                </child>
+                <child>
+                  <widget class="GtkLabel" id="label4">
+                    <property name="visible">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="label" translatable="yes">export functions</property>
+                    <property name="use_markup">True</property>
+                  </widget>
+                  <packing>
+                    <property name="type">label_item</property>
+                  </packing>
+                </child>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+                <property name="pack_type">GTK_PACK_END</property>
+                <property name="position">3</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </widget>
+    </child>
+  </widget>
+</glade-interface>
diff --git a/tests/Demo.hs b/tests/Demo.hs
new file mode 100644
--- /dev/null
+++ b/tests/Demo.hs
@@ -0,0 +1,113 @@
+module Main where
+
+import qualified Data.Number.ER.Real as AERN
+import qualified Data.Number.ER.RnToRm as AERNFunc
+import qualified Data.Number.ER.RnToRm.Plot.FnView as FNV
+
+import Control.Concurrent as Concurrent
+import Control.Concurrent.STM as STM
+
+import qualified Graphics.UI.Gtk as Gtk
+import Graphics.UI.Gtk (AttrOp((:=)))
+import qualified Graphics.UI.Gtk.Glade as Glade
+import qualified Graphics.UI.Gtk.OpenGL as GtkGL
+import qualified Graphics.UI.GLUT as GLUT
+
+type B = AERN.BM
+--type B = AERN.BMPFR
+type RA = AERN.RA B
+type IRA = AERN.IRA B
+type FA = AERNFunc.FAPWP B
+type Box a = AERNFunc.Box a
+type VarID = AERNFunc.VarID
+
+main =
+    do
+    AERN.initialiseBaseArithmetic (0 :: RA)
+    initGtkGL    
+    fadataTV <- newTVarIO faData
+    fndataTV <- newTVarIO FNV.defaultFnData
+    fnviewWindow <- FNV.new (fadataTV, fndataTV) Nothing
+    forkIO $ signalData fndataTV
+    Gtk.mainGUI
+    
+faData = 
+    FNV.defaultFaData
+    {
+        FNV.dataFAs = [f1,f2]
+    }
+
+f1 = AERN.cos ix $ g -- cos(10x)
+f2 = AERNFunc.integrateUnary 3 f1 dom 0 [-1] -- integ(cos(10x)) - 1
+ix = 16
+
+g = AERNFunc.scale 10 x
+
+x :: FA
+x =
+    AERNFunc.bisectUnbisectDepth 5 $
+    AERNFunc.setMaxDegree 3 $
+    AERNFunc.proj xdom 0
+
+xdom = AERNFunc.fromAscList [(0, dom)]
+    
+const01 :: FA
+const01 =
+    AERNFunc.const xdom [0 AERN.\/ 1]
+    
+dom = domL AERN.\/ domR
+(domL, domR) = (-1, 1)
+(valLO, valHI) = (-2,2) 
+
+fnData =
+    setExtents domL domR valLO valHI $ 
+    FNV.defaultFnData
+    {
+        FNV.dataFAsUpdated = True,
+        FNV.dataDomName = "x",
+        FNV.dataFnNames = ["f1","f2"],
+        FNV.dataResultNames = [["y1"],["y2"]],
+        FNV.dataDefaultEvalPoint = 0    
+    }
+
+setExtents left right bot top fnData =
+    fnData
+    {
+        FNV.dataDomL = td left,
+        FNV.dataDomR = td right,
+        FNV.dataValLO = td bot,
+        FNV.dataValHI = td top,
+        FNV.dataDefaultPlotParams =
+            FNV.defaultPlotParams
+            {
+                FNV.pltprmCoordSystem = 
+                    FNV.CoordSystemLinear $
+                        FNV.Rectangle 
+                            (tr $ top + 0.1) 
+                            (tr $ bot - 0.1) 
+                            (tr $ left - 0.1) 
+                            (tr $ right + 0.1) 
+            }        
+    }
+    where
+    tr = toRational . td
+    td = fst . AERN.doubleBounds
+
+initGtkGL =
+    do
+    Gtk.initGUI
+    -- enable multithreaded GUI:
+    Gtk.timeoutAddFull 
+        (Concurrent.yield >> Concurrent.yield >> Concurrent.yield >> return True) 
+        Gtk.priorityDefaultIdle 20
+      -- see http://haskell.org/gtk2hs/archives/2005/07/24/writing-multi-threaded-guis/
+    GtkGL.initGL
+    GLUT.initialize "AERN Function View" [] -- needed for text in GL canvas
+    
+signalData fndataTV =
+    do
+    threadDelay 200000 -- 0.2s
+    atomically $
+        do
+        writeTVar fndataTV fnData
+    
diff --git a/tests/FnView.glade b/tests/FnView.glade
new file mode 100644
--- /dev/null
+++ b/tests/FnView.glade
@@ -0,0 +1,466 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
+<!--Generated with glade3 3.4.5 on Wed Oct  1 15:09:10 2008 -->
+<glade-interface>
+  <widget class="GtkWindow" id="window1">
+    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+    <child>
+      <widget class="GtkHBox" id="hbox1">
+        <property name="visible">True</property>
+        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+        <child>
+          <widget class="GtkVBox" id="vbox1">
+            <property name="visible">True</property>
+            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+            <child>
+              <widget class="GtkFrame" id="frame1">
+                <property name="visible">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="label_xalign">0</property>
+                <property name="shadow_type">GTK_SHADOW_ETCHED_OUT</property>
+                <child>
+                  <widget class="GtkAlignment" id="canvasAlignment1">
+                    <property name="width_request">500</property>
+                    <property name="height_request">500</property>
+                    <property name="visible">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="left_padding">12</property>
+                    <child>
+                      <placeholder/>
+                    </child>
+                  </widget>
+                </child>
+                <child>
+                  <widget class="GtkLabel" id="label1">
+                    <property name="visible">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="label" translatable="yes">plot</property>
+                  </widget>
+                  <packing>
+                    <property name="type">label_item</property>
+                  </packing>
+                </child>
+              </widget>
+            </child>
+            <child>
+              <widget class="GtkHBox" id="hbox2">
+                <property name="visible">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <child>
+                  <widget class="GtkFrame" id="frame2">
+                    <property name="visible">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="label_xalign">0</property>
+                    <property name="shadow_type">GTK_SHADOW_ETCHED_OUT</property>
+                    <child>
+                      <widget class="GtkAlignment" id="alignment2">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="left_padding">12</property>
+                        <child>
+                          <widget class="GtkVBox" id="vbox3">
+                            <property name="visible">True</property>
+                            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                            <child>
+                              <widget class="GtkComboBox" id="coorSystemCombo1">
+                                <property name="visible">True</property>
+                                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                                <property name="items" translatable="yes">log + squeeze
+linear</property>
+                              </widget>
+                            </child>
+                            <child>
+                              <widget class="GtkHBox" id="hbox6">
+                                <property name="visible">True</property>
+                                <child>
+                                  <placeholder/>
+                                </child>
+                              </widget>
+                              <packing>
+                                <property name="position">1</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <widget class="GtkHBox" id="hbox7">
+                                <property name="visible">True</property>
+                                <child>
+                                  <placeholder/>
+                                </child>
+                              </widget>
+                              <packing>
+                                <property name="position">2</property>
+                              </packing>
+                            </child>
+                          </widget>
+                        </child>
+                      </widget>
+                    </child>
+                    <child>
+                      <widget class="GtkLabel" id="label2">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="label" translatable="yes">coord system</property>
+                        <property name="use_markup">True</property>
+                      </widget>
+                      <packing>
+                        <property name="type">label_item</property>
+                      </packing>
+                    </child>
+                  </widget>
+                </child>
+                <child>
+                  <widget class="GtkFrame" id="frame3">
+                    <property name="visible">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="label_xalign">0</property>
+                    <property name="shadow_type">GTK_SHADOW_ETCHED_OUT</property>
+                    <child>
+                      <widget class="GtkAlignment" id="alignment3">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="left_padding">12</property>
+                        <child>
+                          <widget class="GtkTable" id="table2">
+                            <property name="visible">True</property>
+                            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                            <property name="n_rows">4</property>
+                            <property name="n_columns">1</property>
+                            <child>
+                              <placeholder/>
+                            </child>
+                            <child>
+                              <widget class="GtkButton" id="defaultZoomPanButton1">
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="receives_default">True</property>
+                                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                                <property name="label" translatable="yes">set to defaults</property>
+                                <property name="response_id">0</property>
+                              </widget>
+                              <packing>
+                                <property name="y_options">GTK_FILL</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <widget class="GtkHBox" id="hbox4">
+                                <property name="visible">True</property>
+                                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                                <child>
+                                  <widget class="GtkLabel" id="label6">
+                                    <property name="visible">True</property>
+                                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                                    <property name="xalign">0</property>
+                                    <property name="label" translatable="yes">zoom=</property>
+                                  </widget>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <widget class="GtkEntry" id="zoomEntry1">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                                    <property name="width_chars">5</property>
+                                    <property name="truncate_multiline">True</property>
+                                  </widget>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="fill">False</property>
+                                    <property name="position">1</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <widget class="GtkLabel" id="label7">
+                                    <property name="visible">True</property>
+                                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                                    <property name="label" translatable="yes">%</property>
+                                  </widget>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="position">2</property>
+                                  </packing>
+                                </child>
+                              </widget>
+                              <packing>
+                                <property name="top_attach">1</property>
+                                <property name="bottom_attach">2</property>
+                                <property name="y_options">GTK_FILL</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <widget class="GtkTable" id="table3">
+                                <property name="visible">True</property>
+                                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                                <property name="n_rows">2</property>
+                                <property name="n_columns">3</property>
+                                <child>
+                                  <placeholder/>
+                                </child>
+                                <child>
+                                  <placeholder/>
+                                </child>
+                                <child>
+                                  <widget class="GtkLabel" id="label8">
+                                    <property name="visible">True</property>
+                                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                                    <property name="xalign">0</property>
+                                    <property name="label" translatable="yes">centre x=</property>
+                                  </widget>
+                                  <packing>
+                                    <property name="x_options">GTK_FILL</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <widget class="GtkLabel" id="label9">
+                                    <property name="visible">True</property>
+                                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                                    <property name="xalign">0</property>
+                                    <property name="label" translatable="yes">centre y=</property>
+                                  </widget>
+                                  <packing>
+                                    <property name="top_attach">1</property>
+                                    <property name="bottom_attach">2</property>
+                                    <property name="x_options">GTK_FILL</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <widget class="GtkEntry" id="centreXEntry1">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                                    <property name="width_chars">5</property>
+                                  </widget>
+                                  <packing>
+                                    <property name="left_attach">1</property>
+                                    <property name="right_attach">2</property>
+                                    <property name="x_options">GTK_FILL</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <widget class="GtkEntry" id="centreYEntry1">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                                    <property name="width_chars">5</property>
+                                  </widget>
+                                  <packing>
+                                    <property name="left_attach">1</property>
+                                    <property name="right_attach">2</property>
+                                    <property name="top_attach">1</property>
+                                    <property name="bottom_attach">2</property>
+                                    <property name="x_options">GTK_FILL</property>
+                                  </packing>
+                                </child>
+                              </widget>
+                              <packing>
+                                <property name="top_attach">2</property>
+                                <property name="bottom_attach">3</property>
+                                <property name="y_options">GTK_FILL</property>
+                              </packing>
+                            </child>
+                          </widget>
+                        </child>
+                      </widget>
+                    </child>
+                    <child>
+                      <widget class="GtkLabel" id="label3">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="label" translatable="yes">zoom/pan</property>
+                        <property name="use_markup">True</property>
+                      </widget>
+                      <packing>
+                        <property name="type">label_item</property>
+                      </packing>
+                    </child>
+                  </widget>
+                  <packing>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </widget>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </widget>
+        </child>
+        <child>
+          <widget class="GtkVBox" id="vbox2">
+            <property name="visible">True</property>
+            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+            <child>
+              <widget class="GtkHBox" id="hbox5">
+                <property name="visible">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <child>
+                  <widget class="GtkButton" id="defaultEvalPointButton1">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="label" translatable="yes">default</property>
+                    <property name="response_id">0</property>
+                  </widget>
+                </child>
+                <child>
+                  <widget class="GtkLabel" id="domVarLabel1">
+                    <property name="visible">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="label" translatable="yes">==</property>
+                  </widget>
+                  <packing>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="GtkEntry" id="evalPointEntry1">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                  </widget>
+                  <packing>
+                    <property name="position">2</property>
+                  </packing>
+                </child>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+                <property name="padding">2</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkTable" id="dimTable1">
+                <property name="visible">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="resize_mode">GTK_RESIZE_IMMEDIATE</property>
+                <property name="n_rows">4</property>
+                <property name="n_columns">3</property>
+                <property name="column_spacing">1</property>
+                <property name="row_spacing">5</property>
+                <child>
+                  <placeholder/>
+                </child>
+                <child>
+                  <placeholder/>
+                </child>
+                <child>
+                  <placeholder/>
+                </child>
+                <child>
+                  <placeholder/>
+                </child>
+                <child>
+                  <placeholder/>
+                </child>
+                <child>
+                  <placeholder/>
+                </child>
+                <child>
+                  <placeholder/>
+                </child>
+                <child>
+                  <placeholder/>
+                </child>
+                <child>
+                  <placeholder/>
+                </child>
+                <child>
+                  <placeholder/>
+                </child>
+                <child>
+                  <placeholder/>
+                </child>
+                <child>
+                  <placeholder/>
+                </child>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+                <property name="padding">2</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+            <child>
+              <placeholder/>
+            </child>
+            <child>
+              <widget class="GtkFrame" id="frame4">
+                <property name="visible">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="label_xalign">0</property>
+                <property name="shadow_type">GTK_SHADOW_ETCHED_OUT</property>
+                <child>
+                  <widget class="GtkAlignment" id="alignment1">
+                    <property name="visible">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="left_padding">12</property>
+                    <child>
+                      <widget class="GtkHBox" id="hbox3">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <child>
+                          <widget class="GtkButton" id="exportJPGButton1">
+                            <property name="can_focus">True</property>
+                            <property name="receives_default">True</property>
+                            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                            <property name="label" translatable="yes">jpg</property>
+                            <property name="response_id">0</property>
+                          </widget>
+                        </child>
+                        <child>
+                          <widget class="GtkButton" id="printTXTButton1">
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="receives_default">True</property>
+                            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                            <property name="label" translatable="yes">txt</property>
+                            <property name="response_id">0</property>
+                          </widget>
+                          <packing>
+                            <property name="position">1</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <widget class="GtkVBox" id="vbox4">
+                            <property name="visible">True</property>
+                            <child>
+                              <placeholder/>
+                            </child>
+                          </widget>
+                          <packing>
+                            <property name="position">2</property>
+                          </packing>
+                        </child>
+                      </widget>
+                    </child>
+                  </widget>
+                </child>
+                <child>
+                  <widget class="GtkLabel" id="label4">
+                    <property name="visible">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="label" translatable="yes">export functions</property>
+                    <property name="use_markup">True</property>
+                  </widget>
+                  <packing>
+                    <property name="type">label_item</property>
+                  </packing>
+                </child>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+                <property name="pack_type">GTK_PACK_END</property>
+                <property name="position">3</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </widget>
+    </child>
+  </widget>
+</glade-interface>
