changeset 83:06b4504cbcb0

Checkpoint of trying to get a different renderer going (OpenGL)
author daveb
date Mon, 16 Aug 2010 17:16:36 +0930
parents 0314b2e03f9b
children cdd4fc728d94
files builder.d doodle/gtk/cairo_canvas.d doodle/gtk/canvas.d doodle/main/prog/doodler.d doodle/main/prog/gl_example.d options.template
diffstat 6 files changed, 595 insertions(+), 457 deletions(-) [+]
line wrap: on
line diff
--- a/builder.d	Mon Aug 16 00:08:19 2010 +0930
+++ b/builder.d	Mon Aug 16 17:16:36 2010 +0930
@@ -1022,7 +1022,7 @@
 //--------------------------------------------------------------------------------------
 int main(string[] args) {
     int usage() {
-        writefln("Usage: builder <project-path> <build-path>");
+        writeln("Usage: builder <project-path> <build-path>");
         return -1;
     }
 
@@ -1033,8 +1033,14 @@
 
     writefln("building source at %s into %s", sourcePath, Global.buildPath); 
 
-    // do the work
-    scope project = new Project(sourcePath);
+    try {
+        // do the work
+        scope project = new Project(sourcePath);
+    }
+    catch (Exception e) {
+        writeln("Error, bailing");
+        return 1;
+    }
 
     return 0;
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doodle/gtk/cairo_canvas.d	Mon Aug 16 17:16:36 2010 +0930
@@ -0,0 +1,453 @@
+module doodle.gtk.cairo_canvas;
+
+public {
+    import doodle.dia.icanvas;
+    import doodle.gtk.events;
+}
+
+private {
+    import doodle.core.logging;
+    import doodle.tk.screen_model;
+    import doodle.dia.layer_stack;
+    import doodle.gtk.cairo;
+
+    import cairo.Surface;
+    import cairo.Context;
+
+    import gtk.Widget;
+    import gtk.Toolbar;
+    import gtk.Table;
+    import gtk.HRuler;
+    import gtk.VRuler;
+    import gtk.Range;
+    import gtk.HScrollbar;
+    import gtk.VScrollbar;
+    import gtk.DrawingArea;
+    import gtk.Adjustment;
+
+    import gdk.Drawable;
+
+    import gtkc.gtk;
+    import gtkc.gtktypes;
+    //import gtkc.gdktypes;
+
+    import std.math;
+    import std.stdio;
+}
+
+final class Canvas : Table, private IViewport {
+    this(in Layer[] layers, IEventHandler eventHandler, IGrid grid, in double pixelsPerMillimetre) {
+        super(3, 3, 0);
+
+        _damageScreen = Rectangle.DEFAULT;
+
+        _eventHandler = eventHandler;
+        _grid = grid;
+        _pixelsPerMillimetre = pixelsPerMillimetre;
+
+        _layerStack = new LayerStack(layers);
+
+        // Create our child widgets and register callbacks
+
+        _hRuler = new HRuler;
+        attach(_hRuler,
+               1, 2,
+               0, 1,
+               AttachOptions.FILL | AttachOptions.EXPAND, AttachOptions.SHRINK,
+               0, 0);
+        _hRuler.setMetric(MetricType.PIXELS);
+
+        _vRuler = new VRuler;
+        attach(_vRuler,
+               0, 1,
+               1, 2,
+               AttachOptions.SHRINK, AttachOptions.FILL | AttachOptions.EXPAND,
+               0, 0);
+        _vRuler.setMetric(MetricType.PIXELS);
+
+        _drawingArea = new DrawingArea;
+        _drawingArea.addOnRealize(&onRealize);
+        _drawingArea.addOnConfigure(&onConfigure);
+        _drawingArea.addOnExpose(&onExpose);
+        _drawingArea.addOnButtonPress(&onButtonPress);
+        _drawingArea.addOnButtonRelease(&onButtonRelease);
+        _drawingArea.addOnKeyPress(&onKeyPressEvent);
+        _drawingArea.addOnKeyRelease(&onKeyReleaseEvent);
+        _drawingArea.addOnMotionNotify(&onMotionNotify);
+        _drawingArea.addOnScroll(&onScroll);
+        _drawingArea.addOnEnterNotify(&onEnterNotify);
+        _drawingArea.addOnLeaveNotify(&onLeaveNotify);
+
+        _drawingArea.addOnFocusIn(&onFocusIn);
+        _drawingArea.addOnFocusOut(&onFocusOut);
+        _drawingArea.addOnMoveFocus(&onMoveFocus);
+        _drawingArea.addOnGrabBroken(&onGrabBroken);
+        _drawingArea.addOnGrabFocus(&onGrabFocus);
+        _drawingArea.addOnGrabNotify(&onGrabNotify);
+        // addOnPopupMenu
+        // addOnQueryTooltip
+        // addOnSelection*
+        _drawingArea.setEvents(EventMask.EXPOSURE_MASK |
+                               EventMask.POINTER_MOTION_MASK |
+                               EventMask.POINTER_MOTION_HINT_MASK |
+                               EventMask.BUTTON_MOTION_MASK |
+                               EventMask.BUTTON_PRESS_MASK |
+                               EventMask.BUTTON_RELEASE_MASK |
+                               EventMask.KEY_PRESS_MASK |
+                               EventMask.KEY_RELEASE_MASK |
+                               EventMask.ENTER_NOTIFY_MASK |
+                               EventMask.LEAVE_NOTIFY_MASK |
+                               EventMask.FOCUS_CHANGE_MASK |
+                               EventMask.SCROLL_MASK);
+
+        _drawingArea.setCanFocus(true);
+
+        attach(_drawingArea,
+               1, 2,
+               1, 2, 
+               AttachOptions.FILL | AttachOptions.EXPAND, AttachOptions.FILL | AttachOptions.EXPAND,
+               0, 0);
+
+        // value, lower, upper, step-inc, page-inc, page-size
+        // Give the adjustments dummy values until we receive a configure
+        _hAdjustment = new Adjustment(0.0, 0.0, 1.0, 0.2, 0.5, 0.5);
+        _hAdjustment.addOnValueChanged(&onAdjustmentValueChanged);
+        _hScrollbar = new HScrollbar(_hAdjustment);
+        _hScrollbar.setInverted(false);
+        attach(_hScrollbar,
+               1, 2,
+               2, 3,
+               AttachOptions.FILL | AttachOptions.EXPAND,
+               AttachOptions.SHRINK,
+               0, 0);
+
+        _vAdjustment = new Adjustment(0.0, 0.0, 1.0, 0.2, 0.5, 0.5);
+        _vAdjustment.addOnValueChanged(&onAdjustmentValueChanged);
+        _vScrollbar = new VScrollbar(_vAdjustment);
+        _vScrollbar.setInverted(true);
+        attach(_vScrollbar,
+               2, 3,
+               1, 2,
+               AttachOptions.SHRINK,
+               AttachOptions.FILL | AttachOptions.EXPAND,
+               0, 0);
+
+        _cursors = [
+            Cursor.DEFAULT   : CursorType.ARROW,
+            Cursor.HAND      : CursorType.HAND1,
+            Cursor.CROSSHAIR : CursorType.CROSSHAIR,
+            Cursor.PENCIL    : CursorType.PENCIL
+            ];
+    }
+
+    protected {         // XXX the compiler complains about unimplemented methods if this is private
+
+        // IViewport overrides:
+
+        void zoomRelative(in Point screenDatum, in double factor) {
+            _screenModel.zoomRelative(factor, screenDatum);
+            consolidateBounds;
+            updateAdjustments;
+            updateRulers;
+            _grid.zoomChanged(_screenModel.zoom);
+            queueDraw;
+        }
+
+        void panRelative(in Vector screenDisplacement) {
+            _screenModel.panRelativeScreen(screenDisplacement);
+            consolidateBounds;
+            updateAdjustments;
+            updateRulers;
+            queueDraw;
+        }
+
+        void setCursor(in Cursor cursor) {
+            _drawingArea.setCursor(new gdk.Cursor.Cursor(_cursors[cursor]));
+        }
+
+        void damageModel(in Rectangle area) {
+            _damageScreen = _damageScreen | _screenModel.modelToScreen(area);
+        }
+
+        void damageScreen(in Rectangle area) {
+            _damageScreen = _damageScreen | area;
+        }
+    }
+
+    private {
+
+        void initialiseBounds(in Rectangle viewBoundsScreen) {
+            Rectangle layerBounds = _layerStack.bounds;
+            Rectangle paddedLayerBounds = growCentre(layerBounds, 2 * layerBounds.size);
+            _screenModel = new ScreenModel(0.25 * _pixelsPerMillimetre, paddedLayerBounds, viewBoundsScreen);
+            _grid.zoomChanged(_screenModel.zoom);
+
+            updateAdjustments;
+            updateRulers;
+        }
+
+        void consolidateBounds() {
+            Rectangle layerBounds = _layerStack.bounds;
+            Rectangle paddedLayerBounds = growCentre(layerBounds, 2 * layerBounds.size);
+            _screenModel.consolidateCanvasBounds(paddedLayerBounds);
+
+            updateAdjustments;
+            updateRulers;
+        }
+
+        bool onConfigure(GdkEventConfigure * event, Widget widget) {
+            assert(widget is _drawingArea);
+
+            Rectangle viewBoundsScreen = Rectangle(Point(0.0, 0.0), Vector(cast(double)event.width, cast(double)event.height));
+            if (_screenModel is null) { initialiseBounds(viewBoundsScreen); }
+            else { consolidateBounds; }
+
+            return true;
+        }
+
+        bool onExpose(GdkEventExpose * event, Widget widget) {
+            assert(widget is _drawingArea);
+
+            gdk.Drawable.Drawable dr = _drawingArea.getWindow;
+
+            int width, height;
+            dr.getSize(width, height);
+            //trace("Got expose %dx%d\n", width, height);
+
+            scope modelCr = new Context(dr);
+            scope screenCr = new Context(dr);
+
+            Rectangle screenDamage =
+                event is null ? _screenModel.viewBoundsScreen :
+                Rectangle(_screenModel.viewBoundsScreen.position + Vector(cast(double)event.area.x, _screenModel.viewBoundsScreen.h - cast(double)(event.area.y + event.area.height)),
+                          Vector(cast(double)event.area.width, cast(double)event.area.height));
+
+            Rectangle modelDamage = _screenModel.screenToModel(screenDamage);
+
+            modelCr.save; screenCr.save; {
+                {
+                    // Setup model context and clip
+                    modelCr.translate(0.0, _screenModel.viewBoundsScreen.h);
+                    modelCr.scale(_screenModel.zoom, -_screenModel.zoom);
+
+                    immutable Point viewLeftBottom = _screenModel.screenToModel(Point(0.0, 0.0));
+                    modelCr.translate(-viewLeftBottom.x, -viewLeftBottom.y);
+
+                    modelCr.rectangle(modelDamage.x0, modelDamage.y0, modelDamage.w, modelDamage.h);
+                    modelCr.clip;
+                }
+
+                {
+                    // Setup screen context and clip
+                    screenCr.translate(0.0, _screenModel.viewBoundsScreen.h);
+                    screenCr.scale(1.0, -1.0);
+
+                    screenCr.rectangle(screenDamage.x0, screenDamage.y0, screenDamage.w, screenDamage.h);
+                    screenCr.clip;
+                }
+
+                screenCr.save; {
+                    // Fill the background with light grey
+                    screenCr.setSourceRgba(0.9, 0.9, 0.9, 1.0);
+                    screenCr.rectangle(screenDamage.x0, screenDamage.y0, screenDamage.w, screenDamage.h);
+                    screenCr.fill;
+                } screenCr.restore;
+
+                _layerStack.draw(screenDamage, new CairoDrawable(screenCr),
+                                 modelDamage, new CairoDrawable(modelCr));
+            } screenCr.restore; modelCr.restore;
+
+            return true;
+        }
+
+        bool onButtonPress(GdkEventButton * event, Widget widget) {
+            assert(widget is _drawingArea);
+            _eventHandler.handleButtonPress(this, makeButtonEvent(event, _screenModel));
+            fixDamage;
+            return true;
+        }
+
+        bool onButtonRelease(GdkEventButton * event, Widget widget) {
+            assert(widget is _drawingArea);
+            _eventHandler.handleButtonRelease(this, makeButtonEvent(event, _screenModel));
+            fixDamage;
+            return true;
+        }
+
+        bool onKeyPressEvent(GdkEventKey * event, Widget widget) {
+            assert(widget is _drawingArea);
+            _eventHandler.handleKeyPress(this, makeKeyEvent(event, _screenModel));
+            fixDamage;
+            return true;
+        }
+
+        bool onKeyReleaseEvent(GdkEventKey * event, Widget widget) {
+            assert(widget is _drawingArea);
+            _eventHandler.handleKeyRelease(this, makeKeyEvent(event, _screenModel));
+            fixDamage;
+            return true;
+        }
+
+        bool onMotionNotify(GdkEventMotion * event, Widget widget) {
+            assert(widget is _drawingArea);
+
+            // Pass the events on to the rulers so that they update
+            gtk_widget_event(_hRuler.getWidgetStruct(), cast(GdkEvent *)event);
+            gtk_widget_event(_vRuler.getWidgetStruct(), cast(GdkEvent *)event);
+
+            _eventHandler.handleMotion(this, makeMotionEvent(event, _screenModel));
+            fixDamage;
+            return true;
+        }
+
+        bool onScroll(GdkEventScroll * event, Widget widget) {
+            assert(widget is _drawingArea);
+            _eventHandler.handleScroll(this, makeScrollEvent(event, _screenModel));
+            fixDamage;
+            return true;
+        }
+
+        bool onEnterNotify(GdkEventCrossing * event, Widget widget) {
+            assert(widget is _drawingArea);
+            _eventHandler.handleEnter(this, makeCrossingEvent(event, _screenModel));
+            fixDamage;
+            return true;
+        }
+
+        bool onLeaveNotify(GdkEventCrossing * event, Widget widget) {
+            assert(widget is _drawingArea);
+            _eventHandler.handleLeave(this, makeCrossingEvent(event, _screenModel));
+            fixDamage;
+            return true;
+        }
+
+        bool onFocusIn(GdkEventFocus * event, Widget widget) {
+            trace("onFocusIn");
+            return true;
+        }
+
+        bool onFocusOut(GdkEventFocus * event, Widget widget) {
+            trace("onFocusOut");
+            return true;
+        }
+
+        void onMoveFocus(GtkDirectionType direction, Widget widget) {
+            trace("onMoveFocus");
+        }
+
+        bool onGrabBroken(gdk.Event.Event event, Widget widget) {
+            trace("onGrabBroken");
+            return true;
+        }
+
+        void onGrabFocus(Widget widget) {
+            //trace("onGrabFocus");
+        }
+
+        void onGrabNotify(gboolean what, Widget widget){
+            trace("onGrabNotify");
+        }
+
+        void onAdjustmentValueChanged(Adjustment adjustment) {
+            GtkAdjustment * hGtkAdjustment = _hAdjustment.getAdjustmentStruct;
+            GtkAdjustment * vGtkAdjustment = _vAdjustment.getAdjustmentStruct;
+
+            Point oldViewLeftBottom = _screenModel.screenToModel(Point(0.0, 0.0));
+            Point newViewLeftBottom = Point(gtk_adjustment_get_value(hGtkAdjustment),
+                                            gtk_adjustment_get_value(vGtkAdjustment));
+
+            _screenModel.panRelativeModel(newViewLeftBottom - oldViewLeftBottom);
+
+            updateRulers;
+            queueDraw;
+        }
+
+        void updateRulers() {
+            immutable Point viewLeftBottom = _screenModel.screenToModel(_screenModel.viewBoundsScreen.corner0);
+            immutable Point viewRightTop = _screenModel.screenToModel(_screenModel.viewBoundsScreen.corner1);
+
+            // Define these just to obtain the position
+            // below so we can preserve it
+            double lower, upper, position, maxSize;
+
+            _hRuler.getRange(lower, upper, position, maxSize);
+            _hRuler.setRange(viewLeftBottom.x,
+                             viewRightTop.x,
+                             position,
+                             _screenModel.zoom * 50.0);
+
+            _vRuler.getRange(lower, upper, position, maxSize);
+            _vRuler.setRange(viewRightTop.y,
+                             viewLeftBottom.y,
+                             position,
+                             _screenModel.zoom * 50.0);
+        }
+
+        void updateAdjustments() {
+            immutable Point viewLeftBottom = _screenModel.screenToModel(Point(0.0, 0.0));
+            immutable Point viewRightTop = _screenModel.screenToModel(_screenModel.viewBoundsScreen.corner1);
+
+            // Adjust the canvas size if necessary
+            _screenModel.canvasAccommodate(Rectangle(viewLeftBottom, viewRightTop));
+
+            Rectangle viewBoundsModel = _screenModel.viewBoundsModel;
+
+            // Update the adjustments
+
+            GtkAdjustment * hGtkAdjustment = _hAdjustment.getAdjustmentStruct;
+            GtkAdjustment * vGtkAdjustment = _vAdjustment.getAdjustmentStruct;
+
+            gtk_adjustment_set_lower(hGtkAdjustment, _screenModel.canvasBoundsModel.x0);
+            gtk_adjustment_set_upper(hGtkAdjustment, _screenModel.canvasBoundsModel.x1);
+            gtk_adjustment_set_value(hGtkAdjustment, viewLeftBottom.x);
+            gtk_adjustment_set_step_increment(hGtkAdjustment, _screenModel.canvasBoundsModel.w / 16.0);
+            gtk_adjustment_set_page_increment(hGtkAdjustment, _screenModel.canvasBoundsModel.w / 4.0);
+            gtk_adjustment_set_page_size(hGtkAdjustment, viewBoundsModel.w);
+
+            gtk_adjustment_set_lower(vGtkAdjustment, _screenModel.canvasBoundsModel.y0);
+            gtk_adjustment_set_upper(vGtkAdjustment, _screenModel.canvasBoundsModel.y1);
+            gtk_adjustment_set_value(vGtkAdjustment, viewLeftBottom.y);
+            gtk_adjustment_set_step_increment(vGtkAdjustment, _screenModel.canvasBoundsModel.h / 16.0);
+            gtk_adjustment_set_page_increment(vGtkAdjustment, _screenModel.canvasBoundsModel.h / 4.0);
+            gtk_adjustment_set_page_size(vGtkAdjustment, viewBoundsModel.h);
+
+            _hAdjustment.changed;
+            _hAdjustment.valueChanged;
+            _vAdjustment.changed;
+            _vAdjustment.valueChanged;
+        }
+
+        void fixDamage() {
+            if (_damageScreen.valid) {
+                int x, y, w, h;
+                _damageScreen.getQuantised(x, y, w, h);
+                _drawingArea.queueDrawArea(x, cast(int)_screenModel.viewBoundsScreen.h - (y + h), w, h);
+                _damageScreen = Rectangle.DEFAULT;
+            }
+        }
+
+        void onRealize(Widget widget) {
+            assert(widget is _drawingArea);
+            _drawingArea.grabFocus();
+        }
+
+        IEventHandler _eventHandler;
+        IGrid         _grid;
+        double        _pixelsPerMillimetre;
+        LayerStack    _layerStack;
+
+        // Child widgets:
+        HRuler        _hRuler;
+        VRuler        _vRuler;
+        DrawingArea   _drawingArea;
+        Adjustment    _hAdjustment;
+        HScrollbar    _hScrollbar;
+        Adjustment    _vAdjustment;
+        VScrollbar    _vScrollbar;
+
+        Rectangle     _damageScreen;
+        ScreenModel   _screenModel;
+
+        immutable CursorType[Cursor] _cursors;
+    }
+}
--- a/doodle/gtk/canvas.d	Mon Aug 16 00:08:19 2010 +0930
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,453 +0,0 @@
-module doodle.gtk.canvas;
-
-public {
-    import doodle.dia.icanvas;
-    import doodle.gtk.events;
-}
-
-private {
-    import doodle.core.logging;
-    import doodle.tk.screen_model;
-    import doodle.dia.layer_stack;
-    import doodle.gtk.cairo;
-
-    import cairo.Surface;
-    import cairo.Context;
-
-    import gtk.Widget;
-    import gtk.Toolbar;
-    import gtk.Table;
-    import gtk.HRuler;
-    import gtk.VRuler;
-    import gtk.Range;
-    import gtk.HScrollbar;
-    import gtk.VScrollbar;
-    import gtk.DrawingArea;
-    import gtk.Adjustment;
-
-    import gdk.Drawable;
-
-    import gtkc.gtk;
-    import gtkc.gtktypes;
-    //import gtkc.gdktypes;
-
-    import std.math;
-    import std.stdio;
-}
-
-final class Canvas : Table, private IViewport {
-    this(in Layer[] layers, IEventHandler eventHandler, IGrid grid, in double pixelsPerMillimetre) {
-        super(3, 3, 0);
-
-        _damageScreen = Rectangle.DEFAULT;
-
-        _eventHandler = eventHandler;
-        _grid = grid;
-        _pixelsPerMillimetre = pixelsPerMillimetre;
-
-        _layerStack = new LayerStack(layers);
-
-        // Create our child widgets and register callbacks
-
-        _hRuler = new HRuler;
-        attach(_hRuler,
-               1, 2,
-               0, 1,
-               AttachOptions.FILL | AttachOptions.EXPAND, AttachOptions.SHRINK,
-               0, 0);
-        _hRuler.setMetric(MetricType.PIXELS);
-
-        _vRuler = new VRuler;
-        attach(_vRuler,
-               0, 1,
-               1, 2,
-               AttachOptions.SHRINK, AttachOptions.FILL | AttachOptions.EXPAND,
-               0, 0);
-        _vRuler.setMetric(MetricType.PIXELS);
-
-        _drawingArea = new DrawingArea;
-        _drawingArea.addOnRealize(&onRealize);
-        _drawingArea.addOnConfigure(&onConfigure);
-        _drawingArea.addOnExpose(&onExpose);
-        _drawingArea.addOnButtonPress(&onButtonPress);
-        _drawingArea.addOnButtonRelease(&onButtonRelease);
-        _drawingArea.addOnKeyPress(&onKeyPressEvent);
-        _drawingArea.addOnKeyRelease(&onKeyReleaseEvent);
-        _drawingArea.addOnMotionNotify(&onMotionNotify);
-        _drawingArea.addOnScroll(&onScroll);
-        _drawingArea.addOnEnterNotify(&onEnterNotify);
-        _drawingArea.addOnLeaveNotify(&onLeaveNotify);
-
-        _drawingArea.addOnFocusIn(&onFocusIn);
-        _drawingArea.addOnFocusOut(&onFocusOut);
-        _drawingArea.addOnMoveFocus(&onMoveFocus);
-        _drawingArea.addOnGrabBroken(&onGrabBroken);
-        _drawingArea.addOnGrabFocus(&onGrabFocus);
-        _drawingArea.addOnGrabNotify(&onGrabNotify);
-        // addOnPopupMenu
-        // addOnQueryTooltip
-        // addOnSelection*
-        _drawingArea.setEvents(EventMask.EXPOSURE_MASK |
-                               EventMask.POINTER_MOTION_MASK |
-                               EventMask.POINTER_MOTION_HINT_MASK |
-                               EventMask.BUTTON_MOTION_MASK |
-                               EventMask.BUTTON_PRESS_MASK |
-                               EventMask.BUTTON_RELEASE_MASK |
-                               EventMask.KEY_PRESS_MASK |
-                               EventMask.KEY_RELEASE_MASK |
-                               EventMask.ENTER_NOTIFY_MASK |
-                               EventMask.LEAVE_NOTIFY_MASK |
-                               EventMask.FOCUS_CHANGE_MASK |
-                               EventMask.SCROLL_MASK);
-
-        _drawingArea.setCanFocus(true);
-
-        attach(_drawingArea,
-               1, 2,
-               1, 2, 
-               AttachOptions.FILL | AttachOptions.EXPAND, AttachOptions.FILL | AttachOptions.EXPAND,
-               0, 0);
-
-        // value, lower, upper, step-inc, page-inc, page-size
-        // Give the adjustments dummy values until we receive a configure
-        _hAdjustment = new Adjustment(0.0, 0.0, 1.0, 0.2, 0.5, 0.5);
-        _hAdjustment.addOnValueChanged(&onAdjustmentValueChanged);
-        _hScrollbar = new HScrollbar(_hAdjustment);
-        _hScrollbar.setInverted(false);
-        attach(_hScrollbar,
-               1, 2,
-               2, 3,
-               AttachOptions.FILL | AttachOptions.EXPAND,
-               AttachOptions.SHRINK,
-               0, 0);
-
-        _vAdjustment = new Adjustment(0.0, 0.0, 1.0, 0.2, 0.5, 0.5);
-        _vAdjustment.addOnValueChanged(&onAdjustmentValueChanged);
-        _vScrollbar = new VScrollbar(_vAdjustment);
-        _vScrollbar.setInverted(true);
-        attach(_vScrollbar,
-               2, 3,
-               1, 2,
-               AttachOptions.SHRINK,
-               AttachOptions.FILL | AttachOptions.EXPAND,
-               0, 0);
-
-        _cursors = [
-            Cursor.DEFAULT   : CursorType.ARROW,
-            Cursor.HAND      : CursorType.HAND1,
-            Cursor.CROSSHAIR : CursorType.CROSSHAIR,
-            Cursor.PENCIL    : CursorType.PENCIL
-            ];
-    }
-
-    protected {         // XXX the compiler complains about unimplemented methods if this is private
-
-        // IViewport overrides:
-
-        void zoomRelative(in Point screenDatum, in double factor) {
-            _screenModel.zoomRelative(factor, screenDatum);
-            consolidateBounds;
-            updateAdjustments;
-            updateRulers;
-            _grid.zoomChanged(_screenModel.zoom);
-            queueDraw;
-        }
-
-        void panRelative(in Vector screenDisplacement) {
-            _screenModel.panRelativeScreen(screenDisplacement);
-            consolidateBounds;
-            updateAdjustments;
-            updateRulers;
-            queueDraw;
-        }
-
-        void setCursor(in Cursor cursor) {
-            _drawingArea.setCursor(new gdk.Cursor.Cursor(_cursors[cursor]));
-        }
-
-        void damageModel(in Rectangle area) {
-            _damageScreen = _damageScreen | _screenModel.modelToScreen(area);
-        }
-
-        void damageScreen(in Rectangle area) {
-            _damageScreen = _damageScreen | area;
-        }
-    }
-
-    private {
-
-        void initialiseBounds(in Rectangle viewBoundsScreen) {
-            Rectangle layerBounds = _layerStack.bounds;
-            Rectangle paddedLayerBounds = growCentre(layerBounds, 2 * layerBounds.size);
-            _screenModel = new ScreenModel(0.25 * _pixelsPerMillimetre, paddedLayerBounds, viewBoundsScreen);
-            _grid.zoomChanged(_screenModel.zoom);
-
-            updateAdjustments;
-            updateRulers;
-        }
-
-        void consolidateBounds() {
-            Rectangle layerBounds = _layerStack.bounds;
-            Rectangle paddedLayerBounds = growCentre(layerBounds, 2 * layerBounds.size);
-            _screenModel.consolidateCanvasBounds(paddedLayerBounds);
-
-            updateAdjustments;
-            updateRulers;
-        }
-
-        bool onConfigure(GdkEventConfigure * event, Widget widget) {
-            assert(widget is _drawingArea);
-
-            Rectangle viewBoundsScreen = Rectangle(Point(0.0, 0.0), Vector(cast(double)event.width, cast(double)event.height));
-            if (_screenModel is null) { initialiseBounds(viewBoundsScreen); }
-            else { consolidateBounds; }
-
-            return true;
-        }
-
-        bool onExpose(GdkEventExpose * event, Widget widget) {
-            assert(widget is _drawingArea);
-
-            gdk.Drawable.Drawable dr = _drawingArea.getWindow;
-
-            int width, height;
-            dr.getSize(width, height);
-            //trace("Got expose %dx%d\n", width, height);
-
-            scope modelCr = new Context(dr);
-            scope screenCr = new Context(dr);
-
-            Rectangle screenDamage =
-                event is null ? _screenModel.viewBoundsScreen :
-                Rectangle(_screenModel.viewBoundsScreen.position + Vector(cast(double)event.area.x, _screenModel.viewBoundsScreen.h - cast(double)(event.area.y + event.area.height)),
-                          Vector(cast(double)event.area.width, cast(double)event.area.height));
-
-            Rectangle modelDamage = _screenModel.screenToModel(screenDamage);
-
-            modelCr.save; screenCr.save; {
-                {
-                    // Setup model context and clip
-                    modelCr.translate(0.0, _screenModel.viewBoundsScreen.h);
-                    modelCr.scale(_screenModel.zoom, -_screenModel.zoom);
-
-                    immutable Point viewLeftBottom = _screenModel.screenToModel(Point(0.0, 0.0));
-                    modelCr.translate(-viewLeftBottom.x, -viewLeftBottom.y);
-
-                    modelCr.rectangle(modelDamage.x0, modelDamage.y0, modelDamage.w, modelDamage.h);
-                    modelCr.clip;
-                }
-
-                {
-                    // Setup screen context and clip
-                    screenCr.translate(0.0, _screenModel.viewBoundsScreen.h);
-                    screenCr.scale(1.0, -1.0);
-
-                    screenCr.rectangle(screenDamage.x0, screenDamage.y0, screenDamage.w, screenDamage.h);
-                    screenCr.clip;
-                }
-
-                screenCr.save; {
-                    // Fill the background with light grey
-                    screenCr.setSourceRgba(0.9, 0.9, 0.9, 1.0);
-                    screenCr.rectangle(screenDamage.x0, screenDamage.y0, screenDamage.w, screenDamage.h);
-                    screenCr.fill;
-                } screenCr.restore;
-
-                _layerStack.draw(screenDamage, new CairoDrawable(screenCr),
-                                 modelDamage, new CairoDrawable(modelCr));
-            } screenCr.restore; modelCr.restore;
-
-            return true;
-        }
-
-        bool onButtonPress(GdkEventButton * event, Widget widget) {
-            assert(widget is _drawingArea);
-            _eventHandler.handleButtonPress(this, makeButtonEvent(event, _screenModel));
-            fixDamage;
-            return true;
-        }
-
-        bool onButtonRelease(GdkEventButton * event, Widget widget) {
-            assert(widget is _drawingArea);
-            _eventHandler.handleButtonRelease(this, makeButtonEvent(event, _screenModel));
-            fixDamage;
-            return true;
-        }
-
-        bool onKeyPressEvent(GdkEventKey * event, Widget widget) {
-            assert(widget is _drawingArea);
-            _eventHandler.handleKeyPress(this, makeKeyEvent(event, _screenModel));
-            fixDamage;
-            return true;
-        }
-
-        bool onKeyReleaseEvent(GdkEventKey * event, Widget widget) {
-            assert(widget is _drawingArea);
-            _eventHandler.handleKeyRelease(this, makeKeyEvent(event, _screenModel));
-            fixDamage;
-            return true;
-        }
-
-        bool onMotionNotify(GdkEventMotion * event, Widget widget) {
-            assert(widget is _drawingArea);
-
-            // Pass the events on to the rulers so that they update
-            gtk_widget_event(_hRuler.getWidgetStruct(), cast(GdkEvent *)event);
-            gtk_widget_event(_vRuler.getWidgetStruct(), cast(GdkEvent *)event);
-
-            _eventHandler.handleMotion(this, makeMotionEvent(event, _screenModel));
-            fixDamage;
-            return true;
-        }
-
-        bool onScroll(GdkEventScroll * event, Widget widget) {
-            assert(widget is _drawingArea);
-            _eventHandler.handleScroll(this, makeScrollEvent(event, _screenModel));
-            fixDamage;
-            return true;
-        }
-
-        bool onEnterNotify(GdkEventCrossing * event, Widget widget) {
-            assert(widget is _drawingArea);
-            _eventHandler.handleEnter(this, makeCrossingEvent(event, _screenModel));
-            fixDamage;
-            return true;
-        }
-
-        bool onLeaveNotify(GdkEventCrossing * event, Widget widget) {
-            assert(widget is _drawingArea);
-            _eventHandler.handleLeave(this, makeCrossingEvent(event, _screenModel));
-            fixDamage;
-            return true;
-        }
-
-        bool onFocusIn(GdkEventFocus * event, Widget widget) {
-            trace("onFocusIn");
-            return true;
-        }
-
-        bool onFocusOut(GdkEventFocus * event, Widget widget) {
-            trace("onFocusOut");
-            return true;
-        }
-
-        void onMoveFocus(GtkDirectionType direction, Widget widget) {
-            trace("onMoveFocus");
-        }
-
-        bool onGrabBroken(gdk.Event.Event event, Widget widget) {
-            trace("onGrabBroken");
-            return true;
-        }
-
-        void onGrabFocus(Widget widget) {
-            //trace("onGrabFocus");
-        }
-
-        void onGrabNotify(gboolean what, Widget widget){
-            trace("onGrabNotify");
-        }
-
-        void onAdjustmentValueChanged(Adjustment adjustment) {
-            GtkAdjustment * hGtkAdjustment = _hAdjustment.getAdjustmentStruct;
-            GtkAdjustment * vGtkAdjustment = _vAdjustment.getAdjustmentStruct;
-
-            Point oldViewLeftBottom = _screenModel.screenToModel(Point(0.0, 0.0));
-            Point newViewLeftBottom = Point(gtk_adjustment_get_value(hGtkAdjustment),
-                                            gtk_adjustment_get_value(vGtkAdjustment));
-
-            _screenModel.panRelativeModel(newViewLeftBottom - oldViewLeftBottom);
-
-            updateRulers;
-            queueDraw;
-        }
-
-        void updateRulers() {
-            immutable Point viewLeftBottom = _screenModel.screenToModel(_screenModel.viewBoundsScreen.corner0);
-            immutable Point viewRightTop = _screenModel.screenToModel(_screenModel.viewBoundsScreen.corner1);
-
-            // Define these just to obtain the position
-            // below so we can preserve it
-            double lower, upper, position, maxSize;
-
-            _hRuler.getRange(lower, upper, position, maxSize);
-            _hRuler.setRange(viewLeftBottom.x,
-                             viewRightTop.x,
-                             position,
-                             _screenModel.zoom * 50.0);
-
-            _vRuler.getRange(lower, upper, position, maxSize);
-            _vRuler.setRange(viewRightTop.y,
-                             viewLeftBottom.y,
-                             position,
-                             _screenModel.zoom * 50.0);
-        }
-
-        void updateAdjustments() {
-            immutable Point viewLeftBottom = _screenModel.screenToModel(Point(0.0, 0.0));
-            immutable Point viewRightTop = _screenModel.screenToModel(_screenModel.viewBoundsScreen.corner1);
-
-            // Adjust the canvas size if necessary
-            _screenModel.canvasAccommodate(Rectangle(viewLeftBottom, viewRightTop));
-
-            Rectangle viewBoundsModel = _screenModel.viewBoundsModel;
-
-            // Update the adjustments
-
-            GtkAdjustment * hGtkAdjustment = _hAdjustment.getAdjustmentStruct;
-            GtkAdjustment * vGtkAdjustment = _vAdjustment.getAdjustmentStruct;
-
-            gtk_adjustment_set_lower(hGtkAdjustment, _screenModel.canvasBoundsModel.x0);
-            gtk_adjustment_set_upper(hGtkAdjustment, _screenModel.canvasBoundsModel.x1);
-            gtk_adjustment_set_value(hGtkAdjustment, viewLeftBottom.x);
-            gtk_adjustment_set_step_increment(hGtkAdjustment, _screenModel.canvasBoundsModel.w / 16.0);
-            gtk_adjustment_set_page_increment(hGtkAdjustment, _screenModel.canvasBoundsModel.w / 4.0);
-            gtk_adjustment_set_page_size(hGtkAdjustment, viewBoundsModel.w);
-
-            gtk_adjustment_set_lower(vGtkAdjustment, _screenModel.canvasBoundsModel.y0);
-            gtk_adjustment_set_upper(vGtkAdjustment, _screenModel.canvasBoundsModel.y1);
-            gtk_adjustment_set_value(vGtkAdjustment, viewLeftBottom.y);
-            gtk_adjustment_set_step_increment(vGtkAdjustment, _screenModel.canvasBoundsModel.h / 16.0);
-            gtk_adjustment_set_page_increment(vGtkAdjustment, _screenModel.canvasBoundsModel.h / 4.0);
-            gtk_adjustment_set_page_size(vGtkAdjustment, viewBoundsModel.h);
-
-            _hAdjustment.changed;
-            _hAdjustment.valueChanged;
-            _vAdjustment.changed;
-            _vAdjustment.valueChanged;
-        }
-
-        void fixDamage() {
-            if (_damageScreen.valid) {
-                int x, y, w, h;
-                _damageScreen.getQuantised(x, y, w, h);
-                _drawingArea.queueDrawArea(x, cast(int)_screenModel.viewBoundsScreen.h - (y + h), w, h);
-                _damageScreen = Rectangle.DEFAULT;
-            }
-        }
-
-        void onRealize(Widget widget) {
-            assert(widget is _drawingArea);
-            _drawingArea.grabFocus();
-        }
-
-        IEventHandler _eventHandler;
-        IGrid         _grid;
-        double        _pixelsPerMillimetre;
-        LayerStack    _layerStack;
-
-        // Child widgets:
-        HRuler        _hRuler;
-        VRuler        _vRuler;
-        DrawingArea   _drawingArea;
-        Adjustment    _hAdjustment;
-        HScrollbar    _hScrollbar;
-        Adjustment    _vAdjustment;
-        VScrollbar    _vScrollbar;
-
-        Rectangle     _damageScreen;
-        ScreenModel   _screenModel;
-
-        immutable CursorType[Cursor] _cursors;
-    }
-}
--- a/doodle/main/prog/doodler.d	Mon Aug 16 00:08:19 2010 +0930
+++ b/doodle/main/prog/doodler.d	Mon Aug 16 17:16:36 2010 +0930
@@ -1,3 +1,5 @@
+module main.prog.doodler;
+
 private {
     import doodle.core.backtrace;
     import doodle.core.logging;
@@ -13,7 +15,7 @@
 
     import doodle.fig.tools;
 
-    import doodle.gtk.canvas;
+    import doodle.gtk.cairo_canvas;
     import doodle.gtk.palette;
 
     import gtk.Main;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doodle/main/prog/gl_example.d	Mon Aug 16 17:16:36 2010 +0930
@@ -0,0 +1,129 @@
+// File stolen from Gtkd
+
+module main.prog.gl_example;
+
+private import gtk.DrawingArea;
+private import glgtk.GLCapability;
+private import glgdk.GLDrawable;
+private import glgdk.GLConfig;
+private import glgdk.GLContext;
+private import gtkglc.glgdktypes;
+
+private import gtkglc.gl;
+private import gtkglc.glu;
+
+private import gdk.Event;
+
+private import gtk.Widget;
+
+private import gtk.Main;
+private import gtk.MainWindow;
+
+/**
+ * This is a Simple class extending the DrawingArea widget.
+ * A really simple Demo illustrating OpenGL with DUI
+ * It uses the new GLCapability mixin to add the GL capabilities to the widget.
+ * This example is provided under the terms of the GPL License.
+ * Note the initialization of the GLCapabilities on the constructor.
+ * 
+ * @author pac@tuxfamily.org
+ */
+class SimpleGL : DrawingArea {
+    GLfloat width;
+    GLfloat height;
+
+    /** need to include the mixin to add GL capabilities to this widget */
+    mixin GLCapability;
+
+    /**
+     * Construct a simple DrawingArea and sets the GLCapabilities
+     */
+    this() {
+        super(300, 300);
+        setGLCapability();	// set the GL capabilities for this widget
+    }
+
+    /**
+     * put any gl initializations here
+     * returns true to consume the event
+     */
+    bool initGL() {
+        resizeGL(null);
+        return true;
+    }
+
+    /**
+     * This method is called every time the window must be paint or repaint
+     * This is where you put the OpenGL call to draw something.
+     * This method call be called directly by the application without an event object
+     * to force redrawing of the scene.
+     * returns true to consume the event
+     */
+    bool drawGL(GdkEventExpose* event = null) {
+        glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+        glLoadIdentity ();
+
+        gluLookAt(0, 0, 10, 0, 0, 0, 0, 1,0); //Set the camera position
+
+        //Just Draw a tri-colored triangle
+        glBegin(GL_TRIANGLES);
+        glColor3f(1.0f,0.0f,0.0f);
+        glVertex3f( 0.0f, 1.0f, 0.0f);
+        glColor3f(0.0f,1.0f,0.0f);
+        glVertex3f(-1.0f,-1.0f, 0.0f);
+        glColor3f(0.0f,0.0f,1.0f);
+        glVertex3f( 1.0f,-1.0f, 0.0f);
+        glEnd();
+
+        return true;
+    }
+
+    /**
+     * This method is called when the window is resized
+     * returns true to consume the event
+     */
+    bool resizeGL(GdkEventConfigure* event = null) {
+        GLfloat w;
+        GLfloat h;
+
+        if ( event == null ) {
+            w = getWidth();
+            h = getHeight();
+        }
+        else {
+            w = event.width;
+            h = event.height;
+        }
+
+        width = w;
+        height = h;
+
+        glViewport (0, 0, cast(int)w, cast(int)h); //Adjust the viewport according to new window dimensions 
+
+        /*
+         * Update the projection Matrix accoding to the new dimension
+         * and reset the OpenGL state to MODELVIEW
+         */
+        glMatrixMode (GL_PROJECTION);
+        glLoadIdentity ();
+        gluPerspective(20, w/h, 0.1, 10);
+        glMatrixMode (GL_MODELVIEW);
+
+        return true;
+    }
+}
+
+private import glgdk.GLdInit;
+
+void main(string[] args)
+{
+    Main.init(args);
+    GLdInit.init(args);
+
+    SimpleGL simpleGL = new SimpleGL();
+    MainWindow window = new MainWindow("Simplest OpenGL Example");
+    window.add(simpleGL);
+    window.showAll();
+
+    Main.run();
+}
--- a/options.template	Mon Aug 16 00:08:19 2010 +0930
+++ b/options.template	Mon Aug 16 17:16:36 2010 +0930
@@ -1,5 +1,6 @@
 -I~/source/d/dmd/include/d
 -L-lgtkd
+-L-lgtkdgl -L-lGL -L-lGLU
 -L-ldl
 -w
 -wi