diff --git a/CMakeLists.txt b/CMakeLists.txt
index 5bf9e93fdc5eb31ed0e302c5291f3de25567caa0..1c39c2a22976a1f6981012295da7f016ae7b47bd 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -458,6 +458,7 @@ if(ENABLE_BUILD_ANDROID)
   if(NOT CMAKE_TOOLCHAIN_FILE)
     message(SEND_ERROR "Cannot compile Gmsh for android without android-cmake")
   endif(NOT CMAKE_TOOLCHAIN_FILE)
+  set(GMSH_API ${GMSH_API} Common/onelab.h Common/GmshSocket.h Common/onelabUtils.h)
   set(CMAKE_BUILD_TYPE Release)
   set(LIBRARY_OUTPUT_PATH_ROOT ${CMAKE_CURRENT_BINARY_DIR})
   set(LIBRARY_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}/libs/)
diff --git a/contrib/mobile/androidGModel.cpp b/contrib/mobile/androidGModel.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..dfe6e1a0168bc05a42f9205584b14886df994063
--- /dev/null
+++ b/contrib/mobile/androidGModel.cpp
@@ -0,0 +1,226 @@
+#include <android/log.h>
+#include <dlfcn.h>
+
+#define  LOG_TAG    "Gmsh"
+#define  LOGI(...)  __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
+#define  LOGE(...)  __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
+
+#include <gmsh/GModel.h>
+#include <gmsh/onelab.h>
+#include <gmsh/onelabUtils.h>
+#include <gmsh/Context.h>
+#include <gmsh/PView.h>
+#include <gmsh/PViewData.h>
+#include <gmsh/PViewOptions.h>
+
+#include "androidGModel.h"
+#include "drawGModel.h"
+
+onelab::server *getOnelab() {return onelab::server::instance();}
+
+static JavaVM *gJavaVM;
+static JNIEnv *env;
+static jobject gCallbackObject = NULL;
+static jclass jClass;
+
+class MobileMessage : public GmshMessage
+{
+	private:
+	public:
+	MobileMessage(){}
+	~MobileMessage(){}
+	void operator()(std::string level, std::string message)
+	{
+
+		if(level == "Error")
+		{
+			if(message.size() <= 26 || message.substr(message.size()-25,25) != "check the log for details")
+				return;
+			if(!gCallbackObject)
+				return;
+			if ((gJavaVM->AttachCurrentThread(&env, NULL)) < 0)
+				return;
+			jstring jstr = env->NewStringUTF(message.c_str());
+			jclass jClass = env->FindClass("com/example/testlibc/Gmsh"); 
+			if(jClass == 0)
+				return;
+			jmethodID mid = env->GetMethodID(jClass, "ShowPopup", "(Ljava/lang/String;)V");
+			if (mid == 0)
+				return;
+			env->CallVoidMethod(gCallbackObject, mid, jstr);
+			env->DeleteLocalRef(jstr);
+			env->DeleteLocalRef(jClass);
+		}
+		else if(level == "Progress")
+		{
+			if(!gCallbackObject)
+				return;
+			//if ((gJavaVM->GetEnv((void**)&env, JNI_VERSION_1_6)) < 0) 
+			//	return;
+			if ((gJavaVM->AttachCurrentThread(&env, NULL)) < 0)
+				return;
+			jstring jstr = env->NewStringUTF(message.c_str());
+			jclass jClass = env->FindClass("com/example/testlibc/Gmsh"); 
+			if(jClass == 0)
+				return;
+			jmethodID mid = env->GetMethodID(jClass, "SetLoading", "(Ljava/lang/String;)V");
+			if (mid == 0)
+				return;
+			env->CallVoidMethod(gCallbackObject, mid, jstr);
+			env->DeleteLocalRef(jstr);
+			env->DeleteLocalRef(jClass);
+		}
+		else if(level == "RequestRender")
+		{
+			requestRender();
+			return;
+		}
+	 	LOGI("%s", message.c_str());
+	}
+};
+
+void requestRender()
+{
+	if(!gCallbackObject)
+		return;
+	if ((gJavaVM->AttachCurrentThread(&env, NULL)) < 0)
+		return;
+	jclass jClass = env->FindClass("com/example/testlibc/Gmsh"); 
+	if(jClass == 0)
+		return;
+	jmethodID mid = env->GetMethodID(jClass, "RequestRender", "()V");
+	if (mid == 0)
+		return;
+	env->CallVoidMethod(gCallbackObject, mid);
+	env->DeleteLocalRef(jClass);
+}
+
+extern "C" {
+JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) {
+    gJavaVM = vm;
+    return JNI_VERSION_1_6;
+}
+JNIEXPORT jlong JNICALL Java_com_example_testlibc_Gmsh_init
+  (JNIEnv *env, jobject obj, jstring jname)
+{
+	gCallbackObject = env->NewGlobalRef(obj);
+	gJavaVM->GetEnv((void**)&env, JNI_VERSION_1_6);
+	Msg::SetCallback(new MobileMessage());
+	
+	const char*  name = env->GetStringUTFChars(jname, NULL);
+	return reinterpret_cast<jlong>(new drawGModel(name));
+}
+JNIEXPORT void JNICALL Java_com_example_testlibc_Gmsh_loadFile
+  (JNIEnv *env, jobject obj, jlong jptr, jstring jname)
+{
+	const char*  filename = env->GetStringUTFChars(jname, NULL);
+	((drawGModel *)jptr)->load(filename);
+}
+JNIEXPORT void JNICALL Java_com_example_testlibc_Gmsh_initView
+  (JNIEnv *env, jobject obj, jlong jptr, jint w, jint h)
+{
+	((drawGModel *)jptr)->initView(w,h);
+}
+JNIEXPORT void JNICALL Java_com_example_testlibc_Gmsh_drawView
+  (JNIEnv *env, jobject obj, jlong jptr)
+{
+	((drawGModel *)jptr)->drawView();
+}
+JNIEXPORT void JNICALL Java_com_example_testlibc_Gmsh_setTranslation
+  (JNIEnv *env, jobject obj, jlong jptr, jfloat tx, jfloat ty, jfloat tz)
+{
+	((drawGModel *)jptr)->setTranslation(tx, ty, tz);
+}
+JNIEXPORT void JNICALL Java_com_example_testlibc_Gmsh_setScale
+  (JNIEnv *env, jobject obj, jlong jptr, jfloat sx, jfloat sy, jfloat sz)
+{
+	((drawGModel *)jptr)->setScale(sx, sy, sz);
+}
+JNIEXPORT void JNICALL Java_com_example_testlibc_Gmsh_setRotate
+  (JNIEnv *env, jobject obj, jlong jptr, jfloat rx, jfloat ry, jfloat rz)
+{
+	((drawGModel *)jptr)->setRotation(rx, ry, rz);
+}
+JNIEXPORT void JNICALL Java_com_example_testlibc_Gmsh_setShow
+  (JNIEnv *env, jobject obj, jlong jptr, jstring jwhat, jboolean value)
+{
+	const char*  what = env->GetStringUTFChars(jwhat, NULL);
+	if(strcmp(what, "mesh") == 0)
+		((drawGModel *)jptr)->showMesh(value);
+	else if(strcmp(what, "geom") == 0)
+		((drawGModel *)jptr)->showGeom(value);
+}
+JNIEXPORT jlong JNICALL Java_com_example_testlibc_Gmsh_getOnelabInstance
+  (JNIEnv *env , jobject obj)
+{
+	return reinterpret_cast<jlong>(getOnelab());
+}
+
+JNIEXPORT jobjectArray JNICALL Java_com_example_testlibc_Gmsh_getParams
+  (JNIEnv *env, jobject obj)
+{
+	jclass stringClass = env->FindClass( "java/lang/String" );
+	std::vector<std::string> tmp =  onelab::server::instance()->toChar();
+	for(unsigned int i=0;i<tmp.size();i++)
+		for(unsigned int j=0; j<tmp[i].size();j++)
+			if(tmp[i][j] == '\0') tmp[i][j] = '\n';
+	jobjectArray params = env->NewObjectArray(tmp.size(), stringClass, 0);
+	for(int i=0; i<tmp.size();i++){
+		jstring s = env->NewStringUTF(tmp[i].c_str());
+		env->SetObjectArrayElement(params, i, s);
+	}
+	return params;
+}
+
+JNIEXPORT jint JNICALL Java_com_example_testlibc_Gmsh_setParam
+  (JNIEnv *env, jobject obj, jstring jtype, jstring jname, jstring jvalue)
+{
+	const char *type = env->GetStringUTFChars(jtype, NULL);
+	const char *name = env->GetStringUTFChars(jname, NULL);
+	const char *value = env->GetStringUTFChars(jvalue, NULL);
+	// Get the original param and then change the value
+	if(strcmp(type,"ParameterNumber") == 0){
+		std::vector<onelab::number> s;
+		if(onelab::server::instance()->get(s,  name)) s[0].setValue(atof(value));
+		onelab::server::instance()->set(s[0]);
+	}
+	else if(strcmp(type,"ParameterString") == 0){
+		std::vector<onelab::string> s;
+		if(onelab::server::instance()->get(s,  name)) s[0].setValue(value);
+		onelab::server::instance()->set(s[0]);
+	}
+}
+
+JNIEXPORT jobjectArray JNICALL Java_com_example_testlibc_Gmsh_getPView
+  (JNIEnv *env, jobject obj)
+{
+	jclass stringClass = env->FindClass( "java/lang/String" );
+	jobjectArray jPView = env->NewObjectArray(PView::list.size(), stringClass, 0);
+	for(unsigned int i = 0; i < PView::list.size(); i++){
+		std::ostringstream sstream;
+		sstream	<< PView::list[i]->getData()->getName().c_str()
+			<< "\n" <<  PView::list[i]->getOptions()->intervalsType
+			<< "\n" << ((PView::list[i]->getOptions()->visible) ? 1 : 0)
+			<< "\n"  << PView::list[i]->getOptions()->nbIso;
+		jstring s = env->NewStringUTF(sstream.str().c_str());
+		env->SetObjectArrayElement(jPView, i, s);
+	}
+	return jPView;
+}
+
+JNIEXPORT void JNICALL Java_com_example_testlibc_Gmsh_setPView
+  (JNIEnv *env, jobject, jint pos, jint intervalsType, jint visible, jint nIntervals)
+{
+	if(intervalsType > 0 && intervalsType < 4) PView::list[pos]->getOptions()->intervalsType = intervalsType;
+	if(visible >= 0) PView::list[pos]->getOptions()->visible = visible;
+	if(nIntervals > 0) PView::list[pos]->getOptions()->nbIso = nIntervals;
+	PView::list[pos]->setChanged(true);
+}
+
+JNIEXPORT jint JNICALL Java_com_example_testlibc_Gmsh_onelabCB
+  (JNIEnv *env, jobject obj, jstring jaction)
+{
+	const char*  action = env->GetStringUTFChars(jaction, NULL);
+	return onelab_cb(action);
+}
+}
diff --git a/contrib/mobile/androidGModel.h b/contrib/mobile/androidGModel.h
new file mode 100644
index 0000000000000000000000000000000000000000..de9b401283ce5611d0febe8ebb53717b8a55b176
--- /dev/null
+++ b/contrib/mobile/androidGModel.h
@@ -0,0 +1,128 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+/* Header for class com_example_testlibc_Gmsh */
+
+#ifndef _Included_com_example_testlibc_Gmsh
+#define _Included_com_example_testlibc_Gmsh
+
+void requestRender();
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class:     com_example_testlibc_Gmsh
+ * Method:    init
+ * Signature: (Ljava/lang/String;)J
+ */
+JNIEXPORT jlong JNICALL Java_com_example_testlibc_Gmsh_init
+  (JNIEnv *, jobject, jstring);
+
+/*
+ * Class:     com_example_testlibc_Gmsh
+ * Method:    loadFile
+ * Signature: (JLjava/lang/String;)V
+ */
+JNIEXPORT void JNICALL Java_com_example_testlibc_Gmsh_loadFile
+  (JNIEnv *, jobject, jlong, jstring);
+
+/*
+ * Class:     com_example_testlibc_Gmsh
+ * Method:    initView
+ * Signature: (JII)V
+ */
+JNIEXPORT void JNICALL Java_com_example_testlibc_Gmsh_initView
+  (JNIEnv *, jobject, jlong, jint, jint);
+
+/*
+ * Class:     com_example_testlibc_Gmsh
+ * Method:    drawView
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL Java_com_example_testlibc_Gmsh_drawView
+  (JNIEnv *, jobject, jlong);
+
+/*
+ * Class:     com_example_testlibc_Gmsh
+ * Method:    setTranslation
+ * Signature: (JFFF)V
+ */
+JNIEXPORT void JNICALL Java_com_example_testlibc_Gmsh_setTranslation
+  (JNIEnv *, jobject, jlong, jfloat, jfloat, jfloat);
+
+/*
+ * Class:     com_example_testlibc_Gmsh
+ * Method:    setScale
+ * Signature: (JFFF)V
+ */
+JNIEXPORT void JNICALL Java_com_example_testlibc_Gmsh_setScale
+  (JNIEnv *, jobject, jlong, jfloat, jfloat, jfloat);
+
+/*
+ * Class:     com_example_testlibc_Gmsh
+ * Method:    setRotate
+ * Signature: (JFFF)V
+ */
+JNIEXPORT void JNICALL Java_com_example_testlibc_Gmsh_setRotate
+  (JNIEnv *, jobject, jlong, jfloat, jfloat, jfloat);
+
+/*
+ * Class:     com_example_testlibc_Gmsh
+ * Method:    setShow
+ * Signature: (JLjava/lang/String;Z)V
+ */
+JNIEXPORT void JNICALL Java_com_example_testlibc_Gmsh_setShow
+  (JNIEnv *, jobject, jlong, jstring, jboolean);
+
+/*
+ * Class:     com_example_testlibc_Gmsh
+ * Method:    getOnelabInstance
+ * Signature: ()J
+ */
+JNIEXPORT jlong JNICALL Java_com_example_testlibc_Gmsh_getOnelabInstance
+  (JNIEnv *, jobject);
+
+/*
+ * Class:     com_example_testlibc_Gmsh
+ * Method:    getParams
+ * Signature: ()[Ljava/lang/String;
+ */
+JNIEXPORT jobjectArray JNICALL Java_com_example_testlibc_Gmsh_getParams
+  (JNIEnv *, jobject);
+
+/*
+ * Class:     com_example_testlibc_Gmsh
+ * Method:    setParam
+ * Signature: (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I
+ */
+JNIEXPORT jint JNICALL Java_com_example_testlibc_Gmsh_setParam
+  (JNIEnv *, jobject, jstring, jstring, jstring);
+
+/*
+ * Class:     com_example_testlibc_Gmsh
+ * Method:    getPView
+ * Signature: ()[Ljava/lang/String;
+ */
+JNIEXPORT jobjectArray JNICALL Java_com_example_testlibc_Gmsh_getPView
+  (JNIEnv *, jobject);
+
+/*
+ * Class:     com_example_testlibc_Gmsh
+ * Method:    setPView
+ * Signature: (IIII)V
+ */
+JNIEXPORT void JNICALL Java_com_example_testlibc_Gmsh_setPView
+  (JNIEnv *, jobject, jint, jint, jint, jint);
+
+/*
+ * Class:     com_example_testlibc_Gmsh
+ * Method:    onelabCB
+ * Signature: (Ljava/lang/String;)I
+ */
+JNIEXPORT jint JNICALL Java_com_example_testlibc_Gmsh_onelabCB
+  (JNIEnv *, jobject, jstring);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/contrib/mobile/drawGModel.cpp b/contrib/mobile/drawGModel.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..207715824524a02b32014e4a19298ae11f0e5d84
--- /dev/null
+++ b/contrib/mobile/drawGModel.cpp
@@ -0,0 +1,652 @@
+#if !defined(BUILD_ANDROID)
+#define BUILD_IOS 1
+#endif
+
+#include <map>
+
+#if defined(BUILD_IOS)
+#include <OpenGLES/ES1/gl.h>
+#include <OpenGLES/ES1/glext.h>
+
+#include <Gmsh/Gmsh.h>
+#include <Gmsh/GModel.h>
+#include <Gmsh/MElement.h>
+#include <Gmsh/VertexArray.h>
+#include <Gmsh/onelab.h>
+#include <Gmsh/onelabUtils.h>
+#include <Gmsh/PView.h>
+#include <Gmsh/PViewOptions.h>
+#include <Gmsh/Context.h>
+#include <Gmsh/StringUtils.h>
+
+#include <GetDP/GetDP.h>
+#endif
+
+#if defined(BUILD_ANDROID)
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+#include <android/log.h>
+
+#define	LOG_TAG		"Gmsh"
+#define	LOGI(...)	__android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
+#define	LOGE(...)	__android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
+
+#include <gmsh/Gmsh.h>
+#include <gmsh/GModel.h>
+#include <gmsh/MElement.h>
+#include <gmsh/VertexArray.h>
+#include <gmsh/onelab.h>
+#include <gmsh/onelabUtils.h>
+#include <gmsh/PView.h>
+#include <gmsh/PViewOptions.h>
+#include <gmsh/Context.h>
+#include <gmsh/StringUtils.h>
+
+#include <getdp/GetDP.h>
+
+#include "androidGModel.h"
+#endif
+
+#include "drawGModel.h"
+
+drawGModel::drawGModel(std::string name="None")
+{
+	new GModel();
+	GmshInitialize();
+	GmshSetOption("Mesh", "SurfaceFaces", 1.);
+	GmshSetOption("General", "Terminal", 1.);
+	GmshSetOption("General", "Verbosity", 99.);
+	onelabUtils::setFirstComputationFlag(false);
+	for(int i = 0; i < 3; i++){
+		_translation[i] = 0.;
+		_scale[i] = 1.;
+		_rotate[i] = 0.;
+	}
+    
+	_fillMesh = false;
+	_showMesh = false;
+	_showGeom = true;
+	_gradiant = true;
+}
+
+static void checkGlError(const char* op) {
+	for (GLint error = glGetError(); error; error	= glGetError())
+		Msg::Debug("%s: glError (0x%x)",op,error);
+}
+
+static bool locked = false;
+
+void drawGModel::load(std::string filename)
+{
+	if(locked) return;
+	// clear previous GModel, onelab datas and PView
+	GModel::list.clear();
+	PView::list.clear();
+	onelab::server::instance()->clear();
+	
+	// open the file with Gmsh
+	GmshOpenProject(filename);
+    
+	// run getdp witout parameter
+	onelab_cb("check");
+
+	// to allow the firs run
+	onelab::server::instance()->setChanged(true, "Gmsh");
+	onelab::server::instance()->setChanged(true, "GetDP");
+}
+
+void drawGModel::setTranslation(float tx, float ty, float tz)
+{
+	if(tx == 0 && tx == ty && ty == tz)
+		_translation[0] = _translation[1] = _translation[2] = 0;
+	else
+	{
+		_translation[0] += tx * (this->right - this->left); 
+		_translation[1] += ty * (this->right - this->left);
+		_translation[2] += tz * (this->right - this->left);
+	}
+}
+
+void drawGModel::setScale(float sx, float sy, float sz)
+{
+	_scale[0] = sx;
+	_scale[1] = sy ? sy : sx;
+	_scale[2] = sz ? sz : sx;
+}
+
+void drawGModel::setRotation(float rx, float ry, float rz)
+{
+	if(rx == 0 && rx == ry && ry == rz)
+		_rotate[0] = _rotate[1] = _rotate[2] = 0;
+	else
+	{
+		_rotate[0] += rx;
+		_rotate[1] += ry;
+		_rotate[2] += rz;
+	}
+}
+void drawGModel::OrthofFromGModel()
+{
+	SBoundingBox3d bb = GModel::current()->bounds();
+	double ratio = (double)(width ? width : 1.) / (double)(height ? height : 1.);
+	double modelh = bb.max().y() - bb.min().y(), modelw = bb.max().x() - bb.min().x();
+	double modelratio = (modelw ? modelw : 1.) / (modelh ? modelh : 1.);
+	double xmin = -ratio, xmax = ratio, ymin = -1., ymax = 1.;
+  xmin = bb.min().x();
+	xmax = bb.max().x();
+	ymin = bb.min().x() / ratio;
+	ymax = bb.max().x() / ratio;
+	xmax += (xmax - xmin) / 5.;
+	xmin -= (xmax - xmin) / 5.;
+	ymax += (ymax - ymin) / 5.;
+	ymin -= (ymax - ymin) / 5.;
+	
+	// clipping
+	double zmax = std::max(fabs(bb.min().z()), fabs(bb.max().z()));
+	double clip = zmax  * 5.;
+	clip = 1.;
+	
+	glMatrixMode(GL_PROJECTION);
+	glLoadIdentity();
+	glOrthof(xmin, xmax, ymin, ymax, -clip, clip);
+	this->left = xmin; this->right = xmax; this->top = ymax; this->bottom = ymin;
+    
+	glMatrixMode(GL_MODELVIEW);
+}
+void drawGModel::initView(int w, int h)
+{
+	this->height = h;
+	this->width = w;
+	glViewport(0, 0, w, h);
+    
+	this->OrthofFromGModel();
+
+	glClearColor(.83,.85,.98,1.);
+	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+	glLoadIdentity();
+}
+
+void drawArray(VertexArray *va, GLint type, bool colorArray=false)
+{
+	if(!va) return;
+	glEnable(GL_BLEND);
+	glEnable(GL_RESCALE_NORMAL);
+	glShadeModel(GL_SMOOTH);
+	glVertexPointer(3, GL_FLOAT, 0, va->getVertexArray());
+	glEnableClientState(GL_VERTEX_ARRAY);
+	glNormalPointer(GL_BYTE, 0, va->getNormalArray());
+	glEnableClientState(GL_NORMAL_ARRAY);
+	if(colorArray)
+	{
+		glColorPointer(4, GL_UNSIGNED_BYTE, 0, va->getColorArray());
+		glEnableClientState(GL_COLOR_ARRAY);
+	}
+	glDrawArrays(type, 0, va->getNumVertices());
+	glDisable(GL_POLYGON_OFFSET_FILL);
+	glDisableClientState(GL_VERTEX_ARRAY);
+	glDisableClientState(GL_NORMAL_ARRAY);
+	glDisableClientState(GL_COLOR_ARRAY);
+	glDisable(GL_RESCALE_NORMAL);
+	glDisable(GL_BLEND);
+}
+
+void drawVector(double x, double y, double z, double dx, double dy, double dz)
+{
+	double l = sqrt(dx * dx + dy * dy + dz * dz), lt;
+	double n[3], t[3], u[3];
+
+	if(l == 0.0) return;
+
+	GLfloat line[] = {
+		x, y, z,
+		x+dx, y+dy, z+dz,
+  };
+  glVertexPointer(3, GL_FLOAT, 0, line);
+  glEnableClientState(GL_VERTEX_ARRAY);
+  glDrawArrays(GL_LINES, 0, 2);
+	glDisableClientState(GL_VERTEX_ARRAY);
+
+	n[0] = dx / l;
+	n[1] = dy / l;
+	n[2] = dz / l;
+
+	if((fabs(n[0]) >= fabs(n[1]) && fabs(n[0]) >= fabs(n[2])) ||
+		(fabs(n[1]) >= fabs(n[0]) && fabs(n[1]) >= fabs(n[2]))) {
+		t[0] = n[1];
+		t[1] = -n[0];
+		t[2] = 0.;
+	}
+	else {
+		t[0] = 0.;
+		t[1] = n[2];
+		t[2] = -n[1];
+	}
+
+	lt = sqrt(t[0] * t[0] + t[1] * t[1] + t[2] * t[2]);
+	t[0] /= lt;
+	t[1] /= lt;
+	t[2] /= lt;
+
+	u[0] = n[1] * t[2] - n[2] * t[1];
+	u[1] = n[2] * t[0] - n[0] * t[2];
+	u[2] = n[0] * t[1] - n[1] * t[0];
+
+	lt = sqrt(u[0] * u[0] + u[1] * u[1] + u[2] * u[2]);
+	u[0] /= lt;
+	u[1] /= lt;
+	u[2] /= lt;
+
+	double f1 = 0.75; // Stem lenght
+	double b = 0.1 * l;
+	
+	GLfloat arrow[] = {
+		x + dx, y + dy, z + dz,
+		x + f1 * dx + b * (t[0]), y + f1 * dy + b * (t[1]), z + f1 * dz + b * (t[2]),
+		x + f1 * dx + b * (-t[0]), y + f1 * dy + b * (-t[1]), z + f1 * dz + b * (-t[2]),
+
+		x + dx, y + dy, z + dz,
+		x + f1 * dx + b * (-u[0]), y + f1 * dy + b * (-u[1]), z + f1 * dz + b * (-u[2]),
+		x + f1 * dx + b * (u[0]), y + f1 * dy + b * (u[1]), z + f1 * dz + b * (u[2]),
+	};
+  glVertexPointer(3, GL_FLOAT, 0, arrow);
+  glEnableClientState(GL_VERTEX_ARRAY);
+	glEnable(GL_LINE_SMOOTH);
+  glDrawArrays(GL_TRIANGLES, 0, 6);
+	glDisableClientState(GL_VERTEX_ARRAY);
+	glDisable(GL_LINE_SMOOTH);
+
+}
+
+void drawGModel::drawVectorArray(PViewOptions *opt, VertexArray *va)
+{
+	if(!va || va->getNumVerticesPerElement() != 2) return;
+    
+	for(int i = 0; i < va->getNumVertices(); i += 2){
+		float *s = va->getVertexArray(3 * i);
+		float *v = va->getVertexArray(3 * (i + 1));
+		double l = sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
+		double lmax = opt->tmpMax;
+		if((l && opt->vectorType) && lmax)
+		{
+			double scale = (opt->arrowSizeMax - opt->arrowSizeMin) / lmax;
+			if(opt->arrowSizeMin && l) scale += opt->arrowSizeMin / l;
+			double dx = scale * v[0];
+			double dy = scale * v[1];
+			double dz = scale * v[2];
+			GLubyte *color = (GLubyte *)va->getColorArray(4 * i);
+			glColor4ub(*(color), *(color+1), *(color+2), *(color+3));
+			if(fabs(dx) > 1. || fabs(dy) > 1. || fabs(dz) > 1.)
+			{
+				double d = (this->right - this->left) / this->width / _scale[0];
+				dx *= d; dy *= d; dz *= d;
+				double x = s[0], y = s[1], z = s[2];
+				drawVector(x,y,z,dx,dy,dz);
+			}
+		}
+	}
+}
+
+void drawGModel::drawPView(PView *p)
+{
+	PViewOptions *opt = p->getOptions();
+	PViewData *data = p->getData(true);
+	if(!opt->visible) return;
+    
+	glPointSize((GLfloat)opt->pointSize);
+	glLineWidth((GLfloat)opt->lineWidth);
+    
+	drawArray(p->va_points, GL_POINTS,true);
+	drawArray(p->va_lines, GL_LINES,true);
+	drawArray(p->va_triangles, GL_TRIANGLES,true);
+    
+	drawVectorArray(p->getOptions(), p->va_vectors);
+	glLineWidth(1);
+	glPointSize(1);
+}
+
+void drawGModel::drawScale()
+{
+	glPushMatrix();
+	glLoadIdentity();
+	// Draw the scale bar
+	if(PView::list.size() < 1) return;
+	PView *p = PView::list[PView::list.size()-1];
+	PViewOptions *opt = p->getOptions();
+    
+	double width = 6*(this->right -this->left) / 10.;
+	double height = (this->top - this->bottom) / 20.;
+	double box = width / (opt->nbIso ? opt->nbIso : 1);
+	double xmin = this->left + (this->right - this->left -width)/2.;
+	double ymin = this->bottom + height;
+
+    GLfloat *vertex = (GLfloat *)malloc(opt->nbIso*3*4*sizeof(GLfloat));
+    GLubyte *color = (GLubyte *)malloc(opt->nbIso*4*4*sizeof(GLubyte));
+	for(int i = 0; i < opt->nbIso; i++){
+		if(opt->intervalsType == PViewOptions::Discrete || opt->intervalsType == PViewOptions::Numeric)
+		{
+			unsigned int col = opt->getColor(i, opt->nbIso);
+			color[i*4*4+0] = color[i*4*4+4] = color[i*4*4+8] = color[i*4*4+12] = (GLubyte)CTX::instance()->unpackRed(col);
+			color[i*4*4+1] = color[i*4*4+5] = color[i*4*4+9] = color[i*4*4+13] = (GLubyte)CTX::instance()->unpackGreen(col);
+			color[i*4*4+2] = color[i*4*4+6] = color[i*4*4+10] = color[i*4*4+14] = (GLubyte)CTX::instance()->unpackBlue(col);
+			color[i*4*4+3] = color[i*4*4+7] = color[i*4*4+11] = color[i*4*4+15] = (GLubyte)CTX::instance()->unpackAlpha(col);
+			vertex[i*3*4+0] = xmin + i * box;
+			vertex[i*3*4+1] = ymin;
+			vertex[i*3*4+2] = 0.;
+			vertex[i*3*4+3] = xmin + i * box;
+			vertex[i*3*4+4] = ymin + height;
+			vertex[i*3*4+5] = 0.;
+			vertex[i*3*4+6] = xmin + (i + 1) * box;
+			vertex[i*3*4+7] = ymin;
+			vertex[i*3*4+8] = 0.;
+			vertex[i*3*4+9] = xmin + (i + 1) * box;
+			vertex[i*3*4+10] = ymin + height;
+			vertex[i*3*4+11] = 0.;
+		}
+		else if(opt->intervalsType == PViewOptions::Continuous)
+		{
+			double dv = (opt->tmpMax - opt->tmpMin) / (opt->nbIso ? opt->nbIso : 1);
+			double v1 = opt->tmpMin + i * dv;
+			unsigned int col1 = opt->getColor(v1, opt->tmpMin, opt->tmpMax, true);
+			color[i*4*4+0] = color[i*4*4+4] = (GLubyte)CTX::instance()->unpackRed(col1);
+			color[i*4*4+1] = color[i*4*4+5] = (GLubyte)CTX::instance()->unpackGreen(col1);
+			color[i*4*4+2] = color[i*4*4+6] = (GLubyte)CTX::instance()->unpackBlue(col1);
+			color[i*4*4+3] = color[i*4*4+7] = (GLubyte)CTX::instance()->unpackAlpha(col1);
+			vertex[i*3*4+0] = xmin + i * box;
+			vertex[i*3*4+1] = ymin;
+			vertex[i*3*4+2] = 0.;
+			vertex[i*3*4+3] = xmin + i * box;
+			vertex[i*3*4+4] = ymin + height;
+			vertex[i*3*4+5] = 0.;
+			double v2 = opt->tmpMin + (i + 1) * dv;
+            unsigned int col2 = opt->getColor(v2, opt->tmpMin, opt->tmpMax, true);
+			color[i*4*4+8] = color[i*4*4+12] = (GLubyte)CTX::instance()->unpackRed(col2);
+			color[i*4*4+9] = color[i*4*4+13] = (GLubyte)CTX::instance()->unpackGreen(col2);
+			color[i*4*4+10] = color[i*4*4+14] = (GLubyte)CTX::instance()->unpackBlue(col2);
+			color[i*4*4+11] = color[i*4*4+15] = (GLubyte)CTX::instance()->unpackAlpha(col2);
+			vertex[i*3*4+6] = xmin + (i + 1) * box;
+			vertex[i*3*4+7] = ymin;
+			vertex[i*3*4+8] = 0.;
+			vertex[i*3*4+9] = xmin + (i + 1) * box;
+			vertex[i*3*4+10] = ymin + height;
+			vertex[i*3*4+11] = 0.;
+		}
+		else
+		{
+			unsigned int col = opt->getColor(i, opt->nbIso);
+			color[i*4*4+0] = color[i*4*4+4] = color[i*4*4+8] = color[i*4*4+12] = (GLubyte)CTX::instance()->unpackRed(col);
+			color[i*4*4+1] = color[i*4*4+5] = color[i*4*4+9] = color[i*4*4+13] = (GLubyte)CTX::instance()->unpackGreen(col);
+			color[i*4*4+2] = color[i*4*4+6] = color[i*4*4+10] = color[i*4*4+14] = (GLubyte)CTX::instance()->unpackBlue(col);
+			color[i*4*4+3] = color[i*4*4+7] = color[i*4*4+11] = color[i*4*4+15] = (GLubyte)CTX::instance()->unpackAlpha(col);
+			vertex[i*3*4+0] = xmin + i * box;
+			vertex[i*3*4+1] = ymin;
+			vertex[i*3*4+2] = 0.;
+			vertex[i*3*4+3] = xmin + i * box;
+			vertex[i*3*4+4] = ymin + height;
+			vertex[i*3*4+5] = 0.;
+			vertex[i*3*4+6] = xmin + (i + 1) * box;
+			vertex[i*3*4+7] = ymin;
+			vertex[i*3*4+8] = 0.;
+			vertex[i*3*4+9] = xmin + (i + 1) * box;
+			vertex[i*3*4+10] = ymin + height;
+			vertex[i*3*4+11] = 0.;
+		}
+	}
+	
+	{
+    glVertexPointer(3, GL_FLOAT, 0, vertex);
+    glEnableClientState(GL_VERTEX_ARRAY);
+    glColorPointer(4, GL_UNSIGNED_BYTE, 0, color);
+    glEnableClientState(GL_COLOR_ARRAY);
+    if(opt->intervalsType == PViewOptions::Discrete || opt->intervalsType == PViewOptions::Numeric || opt->intervalsType == PViewOptions::Continuous)
+        glDrawArrays(GL_TRIANGLE_STRIP, 0, opt->nbIso*4);
+    else
+        glDrawArrays(GL_LINES, 0, opt->nbIso*4);
+    glDisableClientState(GL_COLOR_ARRAY);
+    glDisableClientState(GL_VERTEX_ARRAY);
+	}
+	free(vertex);
+	free(color);
+	glPopMatrix();
+}
+
+void drawGModel::drawMesh()
+{
+	GModel::current()->fillVertexArrays();
+	glColor4f(0,0,0,1.);
+	for(GModel::fiter it = GModel::current()->firstFace(); it != GModel::current()->lastFace(); it++){
+		if(_fillMesh) drawArray((*it)->va_triangles, GL_TRIANGLES);
+		else drawArray((*it)->va_lines, GL_LINES);
+	}
+}
+
+void drawGModel::drawPost()
+{
+	if(PView::list.empty()) return ;
+    
+	for(unsigned int i = 0; i < PView::list.size(); i++){
+		PView::list[i]->fillVertexArrays();
+		drawPView(PView::list[i]);
+	}
+}
+
+void drawGModel::drawGeom()
+{
+	glColor4f(0,0,1.,1.);
+	glLineWidth(3);
+	for(GModel::eiter it = GModel::current()->firstEdge(); it != GModel::current()->lastEdge(); it++){
+		GEdge *e = *it;
+		int N = e->minimumDrawSegments() + 1;
+		Range<double> t_bounds = e->parBounds(0);
+		double t_min = t_bounds.low();
+		double t_max = t_bounds.high();
+        
+		// Create a VA for this edge
+		GLfloat edge[N*3];
+        
+		for(unsigned int i=0; i < N; i++) {
+			double t = t_min + (double)i / (double)(N-1) * (t_max - t_min);
+			GPoint p = e->point(t);
+			edge[i*3] = p.x(); edge[i*3+1] = p.y(); edge[i*3+2] = p.z();
+		}
+		// Then print the VA
+		glVertexPointer(3, GL_FLOAT, 0, edge);
+		glEnableClientState(GL_VERTEX_ARRAY);
+		glDrawArrays(GL_LINE_STRIP, 0, N);
+		glDisableClientState(GL_VERTEX_ARRAY);
+	}
+	glLineWidth(1);
+}
+
+void drawGModel::drawAxes(double x0, double y0, double z0, double h)
+{
+	glLineWidth(5);
+	glPushMatrix();
+	glLoadIdentity();
+	glTranslatef(x0, y0, z0);
+	glRotatef(this->_rotate[0], 1, 0, 0);
+	glRotatef(this->_rotate[1], 0, 1, 0);
+	glRotatef(this->_rotate[2], 0, 0, 1);
+	glTranslatef(-x0, -y0, -z0);
+
+    const GLfloat axes[] = {
+		(GLfloat)x0, (GLfloat)y0, (GLfloat)z0,
+		(GLfloat)(x0+h), (GLfloat)y0, (GLfloat)z0,
+		(GLfloat)x0, (GLfloat)y0, (GLfloat)z0,
+		(GLfloat)x0, (GLfloat)(y0+h), (GLfloat)z0,
+		(GLfloat)x0, (GLfloat)y0, (GLfloat)z0,
+		(GLfloat)x0, (GLfloat)y0, (GLfloat)(z0+h),
+	};
+    const GLubyte colors[] = {
+        255, 0, 0, 255,
+        255, 0, 0, 255,
+        0, 0, 255, 255,
+        0, 0, 255, 255,
+        0, 255, 0, 255,
+        0, 255, 0, 255,
+    };
+	glVertexPointer(3, GL_FLOAT, 0, axes);
+	glEnableClientState(GL_VERTEX_ARRAY);
+    glColorPointer(4, GL_UNSIGNED_BYTE, 0, colors);
+    glEnableClientState(GL_COLOR_ARRAY);
+	glDrawArrays(GL_LINES, 0, 6);
+	glDisableClientState(GL_VERTEX_ARRAY);
+    glDisableClientState(GL_COLOR_ARRAY);
+	glPopMatrix();
+	glLineWidth(1);
+}
+
+void drawGModel::drawView()
+{
+	this->OrthofFromGModel();
+
+	glMatrixMode(GL_MODELVIEW);
+	// fill the background
+	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+	if(_gradiant)
+	{
+		glPushMatrix();
+		glLoadIdentity();
+		const GLfloat squareVertices[] = {
+			(GLfloat)this->top,	(GLfloat)this->left, -5.,
+			(GLfloat)this->top,	(GLfloat)this->right, -5.,
+			(GLfloat)this->bottom,	(GLfloat)this->left, -5.,
+			(GLfloat)this->bottom,	(GLfloat)this->right, -5.,
+		};
+		const GLubyte squareColors[] = {
+			255, 255, 255, 255,
+			255, 255, 255, 255,
+			190, 200, 255, 255,
+			190, 200, 255, 255,
+		};
+		glVertexPointer(3, GL_FLOAT, 0, squareVertices);
+		glEnableClientState(GL_VERTEX_ARRAY);
+		glColorPointer(4, GL_UNSIGNED_BYTE, 0, squareColors);
+		glEnableClientState(GL_COLOR_ARRAY);
+		glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+		glDisableClientState(GL_COLOR_ARRAY);
+		glPopMatrix();
+	}
+	checkGlError("glError -> drawGradiant");
+	//
+	glLoadIdentity();
+	glRotatef(this->_rotate[0], 1, 0, 0);
+	glRotatef(this->_rotate[1], 0, 1, 0);
+	glRotatef(this->_rotate[2], 0, 0, 1);
+	glTranslatef(this->_translation[0]/this->height,this->_translation[1]/this->width,0);
+	glScalef(this->_scale[0], this->_scale[1], this->_scale[2]);
+	checkGlError("glTranslatef");
+
+	this->drawAxes(this->right - (this->top - this->bottom)/9.0, this->bottom + (this->top - this->bottom)/9.0, 0, (this->top - this->bottom)/10.);
+	this->drawPost();
+	if(_showGeom) this->drawGeom();
+	if(_showMesh) this->drawMesh();
+	this->drawScale();
+	glDisable(GL_LIGHTING);
+	glDisable(GL_LIGHT0);
+	glDisable(GL_DEPTH_TEST);
+}
+
+std::vector<std::string> commandToVector(const std::string cmd)
+{
+	std::vector<std::string> ret;
+	int pos=0, last=0;
+	Msg::Info("Cut: %s", cmd.c_str());
+	while((pos = cmd.find("-", last+1)) != std::string::npos)
+	{
+		ret.push_back(cmd.substr(last,pos-1-last));
+		Msg::Info("Add: %s (%d,%d)", ret[ret.size()-1].c_str(), last, pos-1);
+		last = pos;
+	}
+	ret.push_back(cmd.substr(last,cmd.size()-1));
+	Msg::Info("Add: %s", ret[ret.size()-1].c_str());
+	return ret;
+}
+
+int onelab_cb(std::string action)
+{
+	Msg::Debug("Ask onlab to %s", action.c_str());
+	if(action == "stop")
+	{
+		onelab::string o("GetDP/Action", "stop");
+		o.setVisible(false);
+		o.setNeverChanged(true);
+		onelab::server::instance()->set(o);
+		return 0;
+	}
+	if(locked) return -1;
+	locked = true;
+	int redraw = 0;
+	if(action == "reset")
+	{
+        onelab::server::instance()->clear();
+        onelabUtils::runGmshClient(action, true);
+		action = "check";
+	}
+    
+	Msg::ResetErrorCounter();
+    
+	if(action == "compute")
+	{
+		onelabUtils::initializeLoop("1");
+		onelabUtils::initializeLoop("2");
+		onelabUtils::initializeLoop("3");
+	}
+    
+	do
+	{
+		if(onelabUtils::runGmshClient(action, true))
+			redraw = 1;
+        
+		if(redraw == 0 && !onelab::server::instance()->getChanged("GetDP"))continue;
+
+		std::vector<onelab::string> ps;
+		onelab::server::instance()->get(ps, "GetDP/1ModelName");
+		if(ps.empty()){
+			std::vector<std::string> split = SplitFileName(GModel::current()->getFileName());
+			std::string name(split[0] + split[1]);
+			onelab::string o("GetDP/1ModelName", name, "Model name");
+			o.setKind("file");
+			onelab::server::instance()->set(o);
+		}
+		onelab::string o("GetDP/Action", action);
+		o.setVisible(false);
+		o.setNeverChanged(true);
+		onelab::server::instance()->set(o);
+
+		if(action == "compute")
+		{
+			std::string filename = GModel::current()->getFileName();
+			std::vector<std::string> args;
+			args.push_back("getdp");
+			std::vector<onelab::string> onelabArgs;
+			onelab::server::instance()->get(onelabArgs, "GetDP/1ModelName");
+			args.push_back((onelabArgs.empty())? SplitFileName(filename)[0] + SplitFileName(filename)[1] : onelabArgs[0].getValue());
+			onelab::server::instance()->get(onelabArgs, "GetDP/9ComputeCommand");
+			std::vector<std::string> compute = commandToVector((onelabArgs.empty())? "" : onelabArgs[0].getValue().c_str());
+			args.insert( args.end(), compute.begin(), compute.end() );
+			args.push_back("-onelab");
+			args.push_back("GetDP");
+			GetDP(args, onelab::server::instance());
+		}
+		if(action == "check")
+		{
+			std::string filename = GModel::current()->getFileName();
+			std::vector<std::string> args;
+			args.push_back("getdp");
+			std::vector<onelab::string> onelabArgs;
+			args.push_back(SplitFileName(filename)[0] + SplitFileName(filename)[1]);
+			onelab::server::instance()->get(onelabArgs, "GetDP/9CheckCommand");
+			args.push_back((onelabArgs.empty())? "" : onelabArgs[0].getValue());
+			args.push_back("-onelab");
+			args.push_back("GetDP");
+			GetDP(args, onelab::server::instance());
+		}
+		requestRender();
+	} while(action == "compute" && (onelabUtils::incrementLoop("3") || onelabUtils::incrementLoop("2") || onelabUtils::incrementLoop("1")));
+
+	locked = false;
+
+	return redraw;
+}
+
+// vim:set ts=2:
diff --git a/contrib/mobile/drawGModel.h b/contrib/mobile/drawGModel.h
new file mode 100644
index 0000000000000000000000000000000000000000..36ca1d62c562c14aefb39d9dd4f886ca11a0b34b
--- /dev/null
+++ b/contrib/mobile/drawGModel.h
@@ -0,0 +1,47 @@
+#ifndef _DRAW_GMODEL_H_
+#define _DRAW_GMODEL_H_
+
+#include <string>
+
+int onelab_cb(const std::string);
+
+class drawGModel{
+ private:
+	float _translation[3];
+	float _scale[3];
+	int width, height;
+	double left, right, top, bottom;
+	float ratio;
+	float _rotate[3];
+	bool _gradiant, // show the background gradiant
+		_showGeom, // show the Geometry
+		_showMesh, // show the Mesh
+		_fillMesh; // fill the Mesh
+
+	void OrthofFromGModel(void);
+	void drawPView(PView *p);
+	void drawVectorArray(PViewOptions *opt, VertexArray *va);
+
+ public:
+	drawGModel();
+	drawGModel(std::string name);
+	~drawGModel(){}
+	void load(std::string filename);
+	void setTranslation(float tx, float ty, float tz=0);
+	void setScale(float sx, float sy=0, float sz=0);
+	void setRotation(float rx, float ry, float rz);
+	void initView(int w, int h);
+	void drawView();
+	void drawAxes(double x0=0., double y0=0., double z0=0., double h=0.5);
+	void drawGeom();
+	void drawMesh();
+	void drawPost();
+	void drawScale();
+
+	void useGradiant(bool gradiant=true) {_gradiant = gradiant;}
+	void showGeom(bool show=true) {_showGeom = show;}
+	void showMesh(bool show=true) {_showMesh = show;}
+	void fillMesh(bool show=true) {_fillMesh = show;}
+};
+ 
+#endif