Trigger client paint events on server redraw

See Bug 386833 - [Clientscripting] Support Paint event on Canvas 
diff --git a/bundles/org.eclipse.rap.clientscripting.demo/src/org/eclipse/rap/clientscripting/demo/CustomBehaviors.java b/bundles/org.eclipse.rap.clientscripting.demo/src/org/eclipse/rap/clientscripting/demo/CustomBehaviors.java
index 408add3..d786901 100644
--- a/bundles/org.eclipse.rap.clientscripting.demo/src/org/eclipse/rap/clientscripting/demo/CustomBehaviors.java
+++ b/bundles/org.eclipse.rap.clientscripting.demo/src/org/eclipse/rap/clientscripting/demo/CustomBehaviors.java
@@ -11,6 +11,12 @@
 package org.eclipse.rap.clientscripting.demo;
 
 import org.eclipse.rap.clientscripting.ClientListener;
+import org.eclipse.swt.events.MouseAdapter;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Device;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.swt.layout.GridData;
 import org.eclipse.swt.widgets.Canvas;
 import org.eclipse.swt.widgets.Control;
 import org.eclipse.swt.widgets.Text;
@@ -68,11 +74,28 @@
     listener.addTo( widget, ClientListener.MouseDoubleClick );
   }
 
-  public static void addPaintingBehavior( Canvas canvas ) {
+  public static void addPaintingBehavior( final Canvas canvas ) {
     String scriptCode = ResourceLoaderUtil.readTextContent( RESOURCES_PREFIX + "Painting.js" );
     ClientListener listener = new ClientListener( scriptCode );
+    canvas.addMouseListener( new MouseAdapter() {
+      public void mouseUp( MouseEvent e ) {
+        canvas.setForeground( getRandomColor( canvas.getDisplay() ) );
+        canvas.redraw();
+      }
+    } );
     listener.addTo( canvas, ClientListener.MouseMove );
     listener.addTo( canvas, ClientListener.Paint );
+    canvas.setForeground( getRandomColor( canvas.getDisplay() ) );
+    canvas.redraw();
+  }
+
+  public static Color getRandomColor( Device device ) {
+    RGB rgb = new RGB(
+      ( int )Math.round(  Math.random() * 255 ),
+      ( int )Math.round(  Math.random() * 255 ),
+      ( int )Math.round(  Math.random() * 255 )
+    );
+    return new Color( device, rgb );
   }
 
 }
diff --git a/bundles/org.eclipse.rap.clientscripting.demo/src/org/eclipse/rap/clientscripting/demo/Demo.java b/bundles/org.eclipse.rap.clientscripting.demo/src/org/eclipse/rap/clientscripting/demo/Demo.java
index 9b506fa..9454f91 100644
--- a/bundles/org.eclipse.rap.clientscripting.demo/src/org/eclipse/rap/clientscripting/demo/Demo.java
+++ b/bundles/org.eclipse.rap.clientscripting.demo/src/org/eclipse/rap/clientscripting/demo/Demo.java
@@ -87,7 +87,7 @@
   private void addCanvasExample( Composite parent ) {
     addHeaderLabel( parent, "Canvas:" );
     Canvas canvas = new Canvas( parent, SWT.BORDER );
-    canvas.setLayoutData( new GridData( 250, 250 ) );
+    canvas.setLayoutData( new GridData( SWT.FILL, SWT.FILL, true, true ) );
     CustomBehaviors.addPaintingBehavior( canvas );
   }
 
diff --git a/bundles/org.eclipse.rap.clientscripting.demo/src/org/eclipse/rap/clientscripting/demo/Painting.js b/bundles/org.eclipse.rap.clientscripting.demo/src/org/eclipse/rap/clientscripting/demo/Painting.js
index 695728c..e949f99 100644
--- a/bundles/org.eclipse.rap.clientscripting.demo/src/org/eclipse/rap/clientscripting/demo/Painting.js
+++ b/bundles/org.eclipse.rap.clientscripting.demo/src/org/eclipse/rap/clientscripting/demo/Painting.js
@@ -7,14 +7,15 @@
       event.widget.redraw();
     break;
     case SWT.Paint:
-      event.gc.strokeStyle = "#FF0000";
-      event.gc.lineWidth = 4;
-      event.gc.beginPath();
-      event.gc.moveTo( points[ 0 ][ 0 ], points[ 0 ][ 1 ] );
-      for( var i = 1; i < points.length; i++ ) {
-        event.gc.lineTo( points[ i ][ 0 ] , points[ i ][ 1 ] );
+      if( points.length > 1 ) {
+        event.gc.lineWidth = 4;
+        event.gc.beginPath();
+        event.gc.moveTo( points[ 0 ][ 0 ], points[ 0 ][ 1 ] );
+        for( var i = 1; i < points.length; i++ ) {
+          event.gc.lineTo( points[ i ][ 0 ] , points[ i ][ 1 ] );
+        }
+        event.gc.stroke();
       }
-      event.gc.stroke();
     break;
   }
 };
diff --git a/bundles/org.eclipse.rap.clientscripting/js/org/eclipse/rap/clientscripting/ClientScriptingUtil.js b/bundles/org.eclipse.rap.clientscripting/js/org/eclipse/rap/clientscripting/ClientScriptingUtil.js
index d3a3e33..ff73c4a 100644
--- a/bundles/org.eclipse.rap.clientscripting/js/org/eclipse/rap/clientscripting/ClientScriptingUtil.js
+++ b/bundles/org.eclipse.rap.clientscripting/js/org/eclipse/rap/clientscripting/ClientScriptingUtil.js
@@ -133,7 +133,7 @@
 
   attachControlMethods : function( proxy, source ) {
     proxy.redraw = function() {
-      source.dispatchSimpleEvent( "paint" );
+      org.eclipse.rap.clientscripting.ClientScriptingUtil._initGC( source );
     };
   },
 
@@ -266,19 +266,24 @@
   },
 
   _initPaintEvent : function( event, target ) {
-    var gc = target.getUserData( org.eclipse.rap.clientscripting.WidgetProxy._GC_KEY );
-    if( gc == null ) {
-      gc = this._findExistingGC( target );
-      if( gc == null ) {
-        gc = new org.eclipse.swt.graphics.GC( target );
-      }
-      target.setUserData( org.eclipse.rap.clientscripting.WidgetProxy._GC_KEY, gc );
-    }
-    this._initGC( gc, target );
+    var gc = this._getGCFor( target );
     event.gc = gc.getNativeContext();
   },
 
-  _initGC : function( gc, widget ) {
+  _getGCFor : function( widget ) {
+    var gc = widget.getUserData( org.eclipse.rap.clientscripting.WidgetProxy._GC_KEY );
+    if( gc == null ) {
+      gc = this._findExistingGC( widget );
+      if( gc == null ) {
+        gc = new org.eclipse.swt.graphics.GC( widget );
+      }
+      widget.setUserData( org.eclipse.rap.clientscripting.WidgetProxy._GC_KEY, gc );
+    }
+    return gc;
+  },
+
+  _initGC : function( widget ) {
+    var gc = this._getGCFor( widget );
     var width = widget.getInnerWidth();
     var height = widget.getInnerHeight();
     var fillStyle = widget.getBackgroundColor();
diff --git a/bundles/org.eclipse.rap.clientscripting/js/org/eclipse/rap/clientscripting/EventBinding.js b/bundles/org.eclipse.rap.clientscripting/js/org/eclipse/rap/clientscripting/EventBinding.js
index 6efec5e..5fe77ef 100644
--- a/bundles/org.eclipse.rap.clientscripting/js/org/eclipse/rap/clientscripting/EventBinding.js
+++ b/bundles/org.eclipse.rap.clientscripting/js/org/eclipse/rap/clientscripting/EventBinding.js
@@ -35,13 +35,18 @@
   },
 
   _processEvent : function( event ) {
-    var ClientScriptingUtil = org.eclipse.rap.clientscripting.ClientScriptingUtil;
-    var EventProxy = org.eclipse.rap.clientscripting.EventProxy;
-    var eventProxy = new EventProxy( this._eventType, this._source, event );
-    var wrappedEventProxy = ClientScriptingUtil.wrapAsProto( eventProxy );
-    this._targetFunction.call( wrappedEventProxy );
-    ClientScriptingUtil.postProcessEvent( eventProxy, wrappedEventProxy, event );
-    EventProxy.disposeEventProxy( eventProxy );
+    try {
+      var ClientScriptingUtil = org.eclipse.rap.clientscripting.ClientScriptingUtil;
+      var EventProxy = org.eclipse.rap.clientscripting.EventProxy;
+      var eventProxy = new EventProxy( this._eventType, this._source, event );
+      var wrappedEventProxy = ClientScriptingUtil.wrapAsProto( eventProxy );
+      this._targetFunction.call( wrappedEventProxy );
+      ClientScriptingUtil.postProcessEvent( eventProxy, wrappedEventProxy, event );
+      EventProxy.disposeEventProxy( eventProxy );
+    } catch( ex ) {
+      var msg = "Error in ClientScripting event type ";
+      throw new Error( msg + this._eventType + ": " + ex.message ? ex.message : ex );
+    }
   },
 
   getType : function() {
diff --git a/bundles/org.eclipse.rap.clientscripting/src/org/eclipse/rap/clientscripting/ClientListener.java b/bundles/org.eclipse.rap.clientscripting/src/org/eclipse/rap/clientscripting/ClientListener.java
index c1364a7..0391f91 100644
--- a/bundles/org.eclipse.rap.clientscripting/src/org/eclipse/rap/clientscripting/ClientListener.java
+++ b/bundles/org.eclipse.rap.clientscripting/src/org/eclipse/rap/clientscripting/ClientListener.java
@@ -38,6 +38,10 @@
   public static final int MouseEnter = 6;
   public static final int MouseExit = 7;
   public static final int MouseDoubleClick = SWT.MouseDoubleClick;
+  /**
+   * <strong>Warning: Paint even is only supported on Canvas.</strong>
+   * Using it on other widgets may produce unexpected results.
+   */
   public static final int Paint = 9;
   public static final int FocusIn = SWT.FocusIn;
   public static final int FocusOut = SWT.FocusOut;
diff --git a/tests/org.eclipse.rap.clientscripting.jstest/js/org/eclipse/rap/clientscripting/EventBinding_Test.js b/tests/org.eclipse.rap.clientscripting.jstest/js/org/eclipse/rap/clientscripting/EventBinding_Test.js
index 8900022..e462a0e 100644
--- a/tests/org.eclipse.rap.clientscripting.jstest/js/org/eclipse/rap/clientscripting/EventBinding_Test.js
+++ b/tests/org.eclipse.rap.clientscripting.jstest/js/org/eclipse/rap/clientscripting/EventBinding_Test.js
@@ -411,29 +411,7 @@
       assertEquals( SWT.Modify, logger.log[ 1 ].type );
     },
 
-//  NOTE : For now paint is only triggered explicitly by redraw()
-//    - should also be fired on appear (see below) and resize
-//    testBindPaintEventBeforeAppear : function() {
-//      Processor.processOperation( {
-//        "target" : "w4",
-//        "action" : "create",
-//        "type" : "rwt.widgets.Canvas",
-//        "properties" : {
-//          "style" : [ ],
-//          "parent" : "w2"
-//        }
-//      } );
-//      var canvas = ObjectManager.getObject( "w4" );
-//      var logger = this._createLogger();
-//
-//      new EventBinding( canvas, SWT.Paint, logger );
-//      TestUtil.flush();
-//
-//      assertEquals( 1, logger.log.length );
-//      canvas.destroy();
-//    },
-
-    testBindPaintEventAfterAppear : function() {
+    testBindPaintEvent : function() {
       Processor.processOperation( {
         "target" : "w4",
         "action" : "create",
diff --git a/tests/org.eclipse.rap.clientscripting.jstest/js/org/eclipse/rap/clientscripting/EventProxy_Test.js b/tests/org.eclipse.rap.clientscripting.jstest/js/org/eclipse/rap/clientscripting/EventProxy_Test.js
index 40c12a6..5cb03a9 100644
--- a/tests/org.eclipse.rap.clientscripting.jstest/js/org/eclipse/rap/clientscripting/EventProxy_Test.js
+++ b/tests/org.eclipse.rap.clientscripting.jstest/js/org/eclipse/rap/clientscripting/EventProxy_Test.js
@@ -527,8 +527,8 @@
           "parent" : "w4"
         }
       } );
-      var canvas = ObjectManager.getObject( "w4" );
       var serverGc = ObjectManager.getObject( "w5" );
+      var canvas = ObjectManager.getObject( "w4" );
       TestUtil.flush();
       var gc;
 
@@ -611,6 +611,49 @@
       canvas.destroy();
     },
 
+
+    testPaintEventFromServer : function() {
+      Processor.processOperation( {
+        "target" : "w4",
+        "action" : "create",
+        "type" : "rwt.widgets.Canvas",
+        "properties" : {
+          "style" : [ ],
+          "parent" : "w2"
+        }
+      } );
+      var canvas = ObjectManager.getObject( "w4" );
+      Processor.processOperation( {
+        "target" : "w5",
+        "action" : "create",
+        "type" : "rwt.GC",
+        "properties" : {
+          "parent" : "w4"
+        }
+      } );
+      var serverGc = ObjectManager.getObject( "w5" );
+      TestUtil.flush();
+      var fontArr = [ [ "Arial" ], 11, true, true ];
+      var props;
+
+      new EventBinding( canvas, SWT.Paint, {
+        "call" : function( ev ) {
+          var gc = ev.gc;
+          props = [
+            gc.strokeStyle,
+            gc.fillStyle,
+            qx.ui.core.Font.fromString( gc.font ).toCss()
+          ];
+          gc.strokeStyle = "#ff00ff";
+          gc.fillStyle = "#00ff00";
+        }
+      } );
+      serverGc.init( 500, 500, fontArr, [ 170, 170, 170 ], [ 187, 187, 187 ] );
+
+      assertEquals( [ "#bbbbbb", "#aaaaaa", "italic bold 11px Arial" ], props );
+      canvas.destroy();
+    },
+
     /////////
     // Helper