From f16e531fa37598184537e25248c10315f29611b2 Mon Sep 17 00:00:00 2001
From: Krisjanis Rijnieks <krisjanis.rijnieks@gmail.com>
Date: Fri, 12 Jan 2018 18:12:01 +0100
Subject: [PATCH] Add ofpatch ofAppEGLWindow class that fixes the mouse problem

---
 ofpatch/ofAppEGLWindow.cpp | 2265 ++++++++++++++++++++++++++++++++++++
 ofpatch/ofAppEGLWindow.h   |  310 +++++
 2 files changed, 2575 insertions(+)
 create mode 100644 ofpatch/ofAppEGLWindow.cpp
 create mode 100644 ofpatch/ofAppEGLWindow.h

diff --git a/ofpatch/ofAppEGLWindow.cpp b/ofpatch/ofAppEGLWindow.cpp
new file mode 100644
index 0000000..7db2803
--- /dev/null
+++ b/ofpatch/ofAppEGLWindow.cpp
@@ -0,0 +1,2265 @@
+#include "ofAppEGLWindow.h"
+
+#include "ofGraphics.h" // used in runAppViaInfiniteLoop()
+#include "ofAppRunner.h"
+#include "ofUtils.h"
+#include "ofFileUtils.h"
+#include "ofGLProgrammableRenderer.h"
+#include "ofGLRenderer.h"
+#include <assert.h>
+
+using namespace std;
+
+// native events
+struct udev* udev;
+struct udev_device* dev;
+struct udev_monitor* mon;
+static int udev_fd = -1;
+
+static int keyboard_fd = -1; // defaults to 0 ie console
+
+// minimal map
+const int lowercase_map[] = {
+		0,  0,  '1',  '2',  '3',  '4',  '5', '6',  '7', '8', '9', '0',
+		'-', '=', '\b', '\t', 'q',  'w',  'e', 'r',  't', 'y', 'u', 'i',
+		'o', 'p', '[',  ']',  '\n', 0,   'a', 's',  'd', 'f', 'g', 'h',
+		'j', 'k', 'l',  ';',  '\'',  '\n', 0,  '\\', 'z', 'x', 'c', 'v',
+		'b', 'n', 'm',  ',',  '.',  '/',  0,  '*',  0,  ' ', 0,  0,
+		0,  0,  0,   0,   0,   0,   0,  0,   0,  0,  0,  0, 0,  0, 0,
+		0,  0,  0,   0,   0,   0,   0,  0,   0,  0,  0,  0, 0,  0, 0,
+		0,  0,  0,   0,   0,   0,   0,  0,   0,  0,  0,  '\r'
+
+};
+
+// minimal keyboard map
+const int uppercase_map[] = {
+		0,  0,  '!',  '@',  '#',  '$',  '%', '^',  '&', '*', '(', ')',
+		'_', '+', '\b', '\t', 'Q',  'W',  'E', 'R',  'T', 'Y', 'U', 'I',
+		'O', 'P', '{',  '}',  '\n', 0,   'A', 'S',  'D', 'F', 'G', 'H',
+		'J', 'K', 'L',  ':',  '"', '\n', 0,  '\\', 'Z', 'X', 'C', 'V',
+		'B', 'N', 'M',  '<',  '>',  '?',  0,  '*',  0,  ' ', 0,  0,
+		0,  0,  0,   0,   0,   0,   0,  0,   0,  0,  0,  0, 0,  0, 0,
+		0,  0,  0,   0,   0,   0,   0,  0,   0,  0,  0,  0, 0,  0, 0,
+		0,  0,  0,   0,   0,   0,   0,  0,   0,  0,  0,  '\r'
+};
+
+// keep track of a few things ...
+typedef struct {
+	bool shiftPressed;
+	bool capsLocked;
+} KeyboardState;
+
+static KeyboardState kb;
+
+static struct termios tc;
+static struct termios ots;
+
+typedef struct {
+	int mouseButtonState;
+} MouseState;
+
+// TODO, make this match the upcoming additions to ofWindow
+#define MOUSE_BUTTON_LEFT_MASK		1
+#define MOUSE_BUTTON_MIDDLE_MASK 1 << 1
+#define MOUSE_BUTTON_RIGHT_MASK  2 << 1
+
+static MouseState mb;
+ofAppEGLWindow* ofAppEGLWindow::instance = NULL;
+
+static int string_ends_with(const char *str, const char *suffix) {
+	if (!str || !suffix)
+		return 0;
+	size_t lenstr = strlen(str);
+	size_t lensuffix = strlen(suffix);
+	if (lensuffix > lenstr)
+		return 0;
+	return strncmp(str + lenstr - lensuffix, suffix, lensuffix) == 0;
+}
+
+static int string_begins_with(const char *str, const char *prefix) {
+	if (!str || !prefix)
+		return 0;
+	size_t lenstr = strlen(str);
+	size_t lenprefix = strlen(prefix);
+	if (lenprefix > lenstr)
+		return 0;
+	return strncmp(str, prefix, lenprefix) == 0;
+}
+
+static int dummy_sort(const struct dirent **a,const struct dirent **b) {
+	return 1; // dummy sort
+}
+
+static int filter_kbd(const struct dirent *d) {
+	if(d->d_type != DT_DIR && string_ends_with(d->d_name,"event-kbd")) {
+		return 1;
+	} else {
+		return 0;
+	}
+}
+
+static int filter_mouse(const struct dirent *d) {
+	if(d->d_type != DT_DIR && string_ends_with(d->d_name,"event-mouse")) {
+		return 1;
+	} else {
+		return 0;
+	}
+}
+
+static int filter_event(const struct dirent *d) {
+	if(d->d_type != DT_DIR && string_begins_with(d->d_name,"event")) {
+		return 1;
+	} else {
+		return 0;
+	}
+}
+
+// native
+#define MOUSE_CURSOR_RUN_LENGTH_DECODE(image_buf, rle_data, size, bpp) do \
+		{ unsigned int __bpp; unsigned char *__ip; const unsigned char *__il, *__rd; \
+		__bpp = (bpp); __ip = (image_buf); __il = __ip + (size) * __bpp; \
+		__rd = (rle_data); \
+		while (__ip < __il) { unsigned int __l = *(__rd++); \
+		if (__l & 128) { __l = __l - 128; \
+		do { memcpy (__ip, __rd, 4); __ip += 4; } while (--__l); __rd += 4; \
+		} else { __l *= 4; memcpy (__ip, __rd, __l); \
+		__ip += __l; __rd += __l; } } \
+		} while (0)
+static const struct {
+	unsigned int width;
+	unsigned int height;
+	unsigned int bpp; /* 2:RGB16, 3:RGB, 4:RGBA */
+	unsigned char rle_pixel_data[382 + 1];
+} mouse_cursor_data = {
+		12, 19, 4,
+		"\1\0\0\0\377\213\377\377\377\0\202\0\0\0\377\212\377\377\377\0\3\0\0\0\377"
+		"\377\377\377\377\0\0\0\377\211\377\377\377\0\1\0\0\0\377\202\377\377\377"
+		"\377\1\0\0\0\377\210\377\377\377\0\1\0\0\0\377\203\377\377\377\377\1\0\0"
+		"\0\377\207\377\377\377\0\1\0\0\0\377\204\377\377\377\377\1\0\0\0\377\206"
+		"\377\377\377\0\1\0\0\0\377\205\377\377\377\377\1\0\0\0\377\205\377\377\377"
+		"\0\1\0\0\0\377\206\377\377\377\377\1\0\0\0\377\204\377\377\377\0\1\0\0\0"
+		"\377\207\377\377\377\377\1\0\0\0\377\203\377\377\377\0\1\0\0\0\377\210\377"
+		"\377\377\377\1\0\0\0\377\202\377\377\377\0\1\0\0\0\377\211\377\377\377\377"
+		"\3\0\0\0\377\377\377\377\0\0\0\0\377\212\377\377\377\377\202\0\0\0\377\206"
+		"\377\377\377\377\206\0\0\0\377\203\377\377\377\377\1\0\0\0\377\202\377\377"
+		"\377\377\1\0\0\0\377\204\377\377\377\0\1\0\0\0\377\202\377\377\377\377\3"
+		"\0\0\0\377\377\377\377\0\0\0\0\377\202\377\377\377\377\1\0\0\0\377\203\377"
+		"\377\377\0\3\0\0\0\377\377\377\377\377\0\0\0\377\202\377\377\377\0\1\0\0"
+		"\0\377\202\377\377\377\377\1\0\0\0\377\203\377\377\377\0\202\0\0\0\377\204"
+		"\377\377\377\0\1\0\0\0\377\202\377\377\377\377\1\0\0\0\377\210\377\377\377"
+		"\0\1\0\0\0\377\202\377\377\377\377\1\0\0\0\377\211\377\377\377\0\202\0\0"
+		"\0\377\203\377\377\377\0",
+};
+
+// from http://cantuna.googlecode.com/svn-history/r16/trunk/src/screen.cpp
+#define CASE_STR(x,y) case x: str = y; break
+
+static const char* eglErrorString(EGLint err) {
+	string str;
+	switch (err) {
+	CASE_STR(EGL_SUCCESS, "no error");
+	CASE_STR(EGL_NOT_INITIALIZED, "EGL not, or could not be, initialized");
+	CASE_STR(EGL_BAD_ACCESS, "access violation");
+	CASE_STR(EGL_BAD_ALLOC, "could not allocate resources");
+	CASE_STR(EGL_BAD_ATTRIBUTE, "invalid attribute");
+	CASE_STR(EGL_BAD_CONTEXT, "invalid context specified");
+	CASE_STR(EGL_BAD_CONFIG, "invald frame buffer configuration specified");
+	CASE_STR(EGL_BAD_CURRENT_SURFACE, "current window, pbuffer or pixmap surface is no longer valid");
+	CASE_STR(EGL_BAD_DISPLAY, "invalid display specified");
+	CASE_STR(EGL_BAD_SURFACE, "invalid surface specified");
+	CASE_STR(EGL_BAD_MATCH, "bad argument match");
+	CASE_STR(EGL_BAD_PARAMETER, "invalid paramater");
+	CASE_STR(EGL_BAD_NATIVE_PIXMAP, "invalid NativePixmap");
+	CASE_STR(EGL_BAD_NATIVE_WINDOW, "invalid NativeWindow");
+	CASE_STR(EGL_CONTEXT_LOST, "APM event caused context loss");
+	default: str = "unknown error " + err; break;
+	}
+	return str.c_str();
+}
+
+
+// X11 events
+#include <X11/XKBlib.h>
+
+
+#ifdef TARGET_RASPBERRY_PI
+// TODO: remove these when they enter system headers
+// From : https://github.com/raspberrypi/userland/blob/master/interface/vmcs_host/vc_vchi_dispmanx.h
+#ifndef ELEMENT_CHANGE_LAYER
+#define ELEMENT_CHANGE_LAYER		  (1<<0)
+#endif
+#ifndef ELEMENT_CHANGE_OPACITY
+#define ELEMENT_CHANGE_OPACITY		(1<<1)
+#endif
+#ifndef ELEMENT_CHANGE_DEST_RECT
+#define ELEMENT_CHANGE_DEST_RECT	  (1<<2)
+#endif
+#ifndef ELEMENT_CHANGE_SRC_RECT
+#define ELEMENT_CHANGE_SRC_RECT	   (1<<3)
+#endif
+#ifndef ELEMENT_CHANGE_MASK_RESOURCE
+#define ELEMENT_CHANGE_MASK_RESOURCE  (1<<4)
+#endif
+#ifndef ELEMENT_CHANGE_TRANSFORM
+#define ELEMENT_CHANGE_TRANSFORM	  (1<<5)
+#endif
+#endif
+
+
+//-------------------------------------------------------------------------------------
+ofAppEGLWindow::Settings::Settings()
+:ofGLESWindowSettings(){
+	eglWindowPreference = OF_APP_WINDOW_AUTO;
+	eglWindowOpacity = 255;
+
+	// these are usually set as default, but set them here just to be sure
+	frameBufferAttributes[EGL_RED_SIZE]	 = 8; // 8 bits for red
+	frameBufferAttributes[EGL_GREEN_SIZE]   = 8; // 8 bits for green
+	frameBufferAttributes[EGL_BLUE_SIZE]	= 8; // 8 bits for blue
+	frameBufferAttributes[EGL_ALPHA_SIZE]   = 8; // 8 bits for alpha
+	frameBufferAttributes[EGL_LUMINANCE_SIZE] = EGL_DONT_CARE; // 8 bits for alpha
+	frameBufferAttributes[EGL_DEPTH_SIZE]   = 24; // 24 bits for depth
+	frameBufferAttributes[EGL_STENCIL_SIZE] = 8; // 8 bits for stencil
+	frameBufferAttributes[EGL_SAMPLES]	  = 1;
+
+	initialClearColor = ofColor(0.15 * 255, 0.15 * 255, 0.15 * 255, 255);
+
+	screenNum = 0; /* 0 = LCD on the raspberry pi */
+	layer = 0;
+}
+
+ofAppEGLWindow::Settings::Settings(const ofGLESWindowSettings & settings)
+:ofGLESWindowSettings(settings){
+	eglWindowPreference = OF_APP_WINDOW_AUTO;
+	eglWindowOpacity = 255;
+
+	// these are usually set as default, but set them here just to be sure
+	frameBufferAttributes[EGL_RED_SIZE]	 = 8; // 8 bits for red
+	frameBufferAttributes[EGL_GREEN_SIZE]   = 8; // 8 bits for green
+	frameBufferAttributes[EGL_BLUE_SIZE]	= 8; // 8 bits for blue
+	frameBufferAttributes[EGL_ALPHA_SIZE]   = 8; // 8 bits for alpha
+	frameBufferAttributes[EGL_LUMINANCE_SIZE] = EGL_DONT_CARE; // 8 bits for alpha
+	frameBufferAttributes[EGL_DEPTH_SIZE]   = 24; // 24 bits for depth
+	frameBufferAttributes[EGL_STENCIL_SIZE] = 8; // 8 bits for stencil
+	frameBufferAttributes[EGL_SAMPLES]	  = 1;
+
+	initialClearColor = ofColor(0.15 * 255, 0.15 * 255, 0.15 * 255, 255);
+
+	screenNum = 0; /* 0 = LCD on the raspberry pi */
+	layer = 0;
+}
+
+//------------------------------------------------------------
+ofAppEGLWindow::ofAppEGLWindow() {
+	keyboardDetected = false;
+	mouseDetected = false;
+	threadTimeout = ofThread::INFINITE_JOIN_TIMEOUT;
+	bNewScreenMode = false;
+	buttonInUse = -1;
+	bEnableSetupScreen = false;
+	bShowCursor = true;
+	nFramesSinceWindowResized = 0;
+	mouseScaleX = 2.0f;
+	mouseScaleY = 2.0f;
+	isUsingX11 = false;
+	isWindowInited = false;
+	isSurfaceInited = false;
+	x11Display = NULL;
+	x11Screen = NULL;
+	x11ScreenNum = 0l;
+	glesVersion = 1;
+
+	if(instance!=NULL){
+		ofLogError("ofAppEGLWindow") << "trying to create more than one instance";
+	}
+	instance = this;
+}
+
+//------------------------------------------------------------
+ofAppEGLWindow::~ofAppEGLWindow() {
+	close();
+}
+
+//------------------------------------------------------------
+EGLDisplay ofAppEGLWindow::getEglDisplay() const {
+	return eglDisplay;
+}
+
+//------------------------------------------------------------
+EGLSurface ofAppEGLWindow::getEglSurface() const {
+	return eglSurface;
+}
+
+//------------------------------------------------------------
+EGLContext ofAppEGLWindow::getEglContext() const {
+	return eglContext;
+}
+
+#ifndef TARGET_RASPBERRY_PI
+//------------------------------------------------------------
+Display* ofAppEGLWindow::getX11Display(){
+	return x11Display;
+}
+
+//------------------------------------------------------------
+Window ofAppEGLWindow::getX11Window(){
+	return x11Window;
+}
+#endif
+//------------------------------------------------------------
+EGLConfig ofAppEGLWindow::getEglConfig() const {
+	return eglConfig;
+}
+
+//------------------------------------------------------------
+EGLint ofAppEGLWindow::getEglVersionMajor () const {
+	return eglVersionMajor;
+}
+
+//------------------------------------------------------------
+EGLint ofAppEGLWindow::getEglVersionMinor() const {
+	return eglVersionMinor;
+}
+
+//------------------------------------------------------------
+void ofAppEGLWindow::initNative() {
+#ifdef TARGET_RASPBERRY_PI
+	initRPiNative();
+#endif
+}
+
+//------------------------------------------------------------
+void ofAppEGLWindow::exitNative() {
+#ifdef TARGET_RASPBERRY_PI
+	exitRPiNative();
+#endif
+}
+
+//------------------------------------------------------------
+EGLNativeWindowType ofAppEGLWindow::getNativeWindow()  {
+	if(!isWindowInited) {
+		ofLogWarning("ofAppEGLWindow") << "getNativeDisplay(): window not initialized, returning NULL";
+		return NULL;
+	}
+
+	if(isUsingX11) {
+		return (EGLNativeWindowType)x11Window;
+	} else {
+#ifdef TARGET_RASPBERRY_PI
+		return (EGLNativeWindowType)&dispman_native_window;
+#else
+		ofLogNotice("ofAppEGLWindow") << "getNativeWindow(): no native window type for this system, perhaps try X11?";
+		return NULL;
+#endif
+	}
+}
+
+//------------------------------------------------------------
+EGLNativeDisplayType ofAppEGLWindow::getNativeDisplay() {
+	if(!isWindowInited) {
+		ofLogWarning("ofAppEGLWindow") << "getNativeDisplay(): window not initialized, returning NULL";
+		return 0;
+	}
+
+	if(isUsingX11) {
+		return (EGLNativeDisplayType)x11Display;
+	} else {
+#ifdef TARGET_RASPBERRY_PI
+		return (EGLNativeDisplayType)NULL;
+#else
+		ofLogNotice("ofAppEGLWindow") << "getNativeDisplay(): no native window type for this system, perhaps try X11?";
+		return 0;
+#endif
+	}
+}
+
+//------------------------------------------------------------
+void ofAppEGLWindow::setup(const ofGLESWindowSettings & settings){
+	const Settings * glSettings = dynamic_cast<const Settings*>(&settings);
+	if(glSettings){
+		setup(*glSettings);
+	}else{
+		setup(Settings(settings));
+	}
+}
+
+//------------------------------------------------------------
+void ofAppEGLWindow::setup(const Settings & _settings) {
+	settings = _settings;
+	windowMode = OF_WINDOW;
+	bNewScreenMode = true;
+	nFramesSinceWindowResized = 0;
+	buttonInUse	= 0;
+	bEnableSetupScreen = true;
+	eglDisplayString = "";
+	orientation = OF_ORIENTATION_DEFAULT;
+
+	//TODO: 2.0f is an arbitrary factor that makes mouse speed ok at 1024x768,
+	// to be totally correct we might need to take into account screen size
+	// and add acceleration
+	mouseScaleX = 2.0f;
+	mouseScaleY = 2.0f;
+
+	isUsingX11 = false;
+	isWindowInited  = false;
+	isSurfaceInited = false;
+
+	eglDisplay = NULL;
+	eglSurface = NULL;
+	eglContext = NULL;
+	eglConfig  = NULL;
+	eglVersionMajor = -1;
+	eglVersionMinor = -1;
+	glesVersion = 1;
+
+	// X11 check
+	// char * pDisplay;
+	// pDisplay = getenv ("DISPLAY");
+	// bool bIsX11Available = (pDisplay != NULL);
+
+	bool bIsX11Available = getenv("DISPLAY") != NULL;
+
+	if(settings.eglWindowPreference == OF_APP_WINDOW_AUTO) {
+		if(bIsX11Available) {
+			isUsingX11 = true;
+		} else {
+			isUsingX11 = false;
+		}
+	} else if(settings.eglWindowPreference == OF_APP_WINDOW_NATIVE) {
+		isUsingX11 = false;
+	} else if(settings.eglWindowPreference == OF_APP_WINDOW_X11) {
+		isUsingX11 = true;
+		if(!bIsX11Available) {
+			isUsingX11 = false;
+			ofLogError("ofAppEGLWindow") << "init(): X11 window requested, but X11 is not available";
+		}
+	}
+
+	////////////////
+	// TODO remove the following ifdef once x11 is accelerated on RPI
+#ifdef TARGET_RASPBERRY_PI
+	if(isUsingX11) {
+		isUsingX11 = false;
+		ofLogWarning("ofAppEGLWindow") << "init(): X11 not availble on RPI yet, using a native window instead";
+	}
+#endif
+	////////////////
+
+	initNative();
+
+	glesVersion = settings.glesVersion;
+	// we set this here, and if we need to make a fullscreen
+	// app, we do it during the first loop.
+	windowMode = settings.windowMode;
+	bShowCursor = true;
+
+	nonFullscreenWindowRect.set(0,0,settings.width,settings.height);
+	nonFullscreenWindowRect.standardize();
+
+	ofRectangle startRect = nonFullscreenWindowRect;
+	bNewScreenMode = false;
+
+	if(windowMode == OF_GAME_MODE) {
+		ofLogWarning("ofAppEGLWindow") << "setupOpenGL(): OF_GAME_MODE not supported, using OF_WINDOW";
+		startRect = nonFullscreenWindowRect;
+	} else if(windowMode == OF_FULLSCREEN) {
+		startRect = getScreenRect();
+	}
+
+	isWindowInited = createWindow(startRect);
+	isSurfaceInited = createSurface();
+
+	if(!isWindowInited) {
+		ofLogError("ofAppEGLWindow")  << "setupOpenGL(): screen creation failed, window not inited";
+	}
+
+	setupPeripherals();
+
+	nFramesSinceWindowResized = 0;
+
+	if(settings.glesVersion>1){
+		currentRenderer = make_shared<ofGLProgrammableRenderer>(this);
+	}else{
+		currentRenderer = make_shared<ofGLRenderer>(this);
+	}
+
+	makeCurrent();
+	if(currentRenderer->getType()==ofGLProgrammableRenderer::TYPE){
+		static_cast<ofGLProgrammableRenderer*>(currentRenderer.get())->setup(settings.glesVersion,0);
+	}else{
+		static_cast<ofGLRenderer*>(currentRenderer.get())->setup();
+	}
+}
+
+//------------------------------------------------------------
+void ofAppEGLWindow::setupPeripherals() {
+	if(!isUsingX11) {
+		// roll our own cursor!
+		mouseCursor.allocate(mouse_cursor_data.width,mouse_cursor_data.height,OF_IMAGE_COLOR_ALPHA);
+		MOUSE_CURSOR_RUN_LENGTH_DECODE(mouseCursor.getPixels().getData(),mouse_cursor_data.rle_pixel_data,mouse_cursor_data.width*mouse_cursor_data.height,mouse_cursor_data.bpp);
+		mouseCursor.update();
+		ofLogNotice("ofAppEGLWindow") << "setupPeripherals(): peripheral setup complete";
+		setupNativeEvents();
+		ofLogNotice("ofAppEGLWindow") << "setupPeripherals(): native event setup complete";
+
+	} else {
+		ofLogError("ofAppEGLWindow") << "setupPeripherals(): peripherals not supported on X11";
+	}
+}
+
+//------------------------------------------------------------
+bool ofAppEGLWindow::createSurface() {
+
+	EGLNativeWindowType nativeWindow = getNativeWindow();
+	EGLNativeDisplayType display = getNativeDisplay();
+
+	ofLogNotice("ofAppEGLWindow") << "createSurface(): setting up EGL Display";
+	// get an EGL eglDisplay connection
+
+	isSurfaceInited = false;
+
+	EGLint result;
+
+	if(display==0){
+		eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+	}else{
+		eglDisplay = eglGetDisplay(display);
+	}
+
+	if(eglDisplay == EGL_NO_DISPLAY) {
+		ofLogNotice("ofAppEGLWindow") << "createSurface(): eglGetDisplay returned: " << eglDisplay;
+		return false;
+	}else{
+		ofLogNotice("ofAppEGLWindow") << "createSurface(): EGL Display correctly set " << eglDisplay;
+	}
+
+	// initialize the EGL eglDisplay connection
+	result = eglInitialize(eglDisplay,
+			&eglVersionMajor,
+			&eglVersionMinor);
+
+	if(result == EGL_BAD_DISPLAY) {
+		//  eglDisplay is not an EGL connection
+		ofLogError("ofAppEGLWindow") << "createSurface(): eglInitialize returned EGL_BAD_DISPLAY";
+		return false;
+	} else if(result == EGL_NOT_INITIALIZED) {
+		// eglDisplay cannot be intitialized
+		ofLogError("ofAppEGLWindow") << "createSurface(): eglInitialize returned EGL_NOT_INITIALIZED";
+		return false;
+	} else if(result == EGL_FALSE) {
+		// eglinitialize was not initialiezd
+		ofLogError("ofAppEGLWindow") << "createSurface(): eglInitialize returned EGL_FALSE";
+		return false;
+	} else {
+		// result == EGL_TRUE
+		// success!
+	}
+
+	EGLint glesVersion;
+	int glesVersionForContext;
+
+	if(ofGetCurrentRenderer()) {
+		ofLogNotice("ofAppEGLWindow") << "createSurface(): current renderer type: " << ofGetCurrentRenderer()->getType();
+	} else {
+		ofLogNotice("ofAppEGLWindow") << "createSurface(): no current renderer selected";
+	}
+
+	if(this->glesVersion==2){
+		glesVersion = EGL_OPENGL_ES2_BIT;
+		glesVersionForContext = 2;
+		ofLogNotice("ofAppEGLWindow") << "createSurface(): GLES2 renderer detected";
+	}else{
+		glesVersion = EGL_OPENGL_ES_BIT;
+		glesVersionForContext = 1;
+		ofLogNotice("ofAppEGLWindow") << "createSurface(): default renderer detected";
+	}
+
+	ofEGLAttributeListIterator iter, iterEnd;
+	int i;
+
+	// each attribute has 2 values, and we need one extra for the EGL_NONE terminator
+	EGLint attribute_list_framebuffer_config[settings.frameBufferAttributes.size() * 2 + 3];
+
+	iter = settings.frameBufferAttributes.begin();
+	iterEnd = settings.frameBufferAttributes.end();
+	i = 0;
+	for(; iter != iterEnd; iter++) {
+		attribute_list_framebuffer_config[i++] = iter->first;
+		attribute_list_framebuffer_config[i++] = iter->second;
+	}
+	attribute_list_framebuffer_config[i++] = EGL_RENDERABLE_TYPE;
+	attribute_list_framebuffer_config[i++] = glesVersion; //openGL ES version
+	attribute_list_framebuffer_config[i] = EGL_NONE; // add the terminator
+
+	EGLint num_configs;
+
+	// get an appropriate EGL frame buffer configuration
+	// http://www.khronos.org/registry/egl/sdk/docs/man/xhtml/eglChooseConfig.html
+	result = eglChooseConfig(eglDisplay,
+			attribute_list_framebuffer_config,
+			&eglConfig,
+			1, // we only want the first one.  if we want more,
+			// we need to pass in an array.
+			// we are optimistic and don't give it more chances
+			// to find a good configuration
+			&num_configs);
+
+	if(result == EGL_FALSE) {
+		EGLint error = eglGetError();
+		ofLogError("ofAppEGLWindow") << "createSurface(): error finding valid configuration based on settings: " << eglErrorString(error);
+		return false;
+	}
+
+	if(num_configs <= 0 || eglConfig == NULL) {
+		ofLogError("ofAppEGLWindow") << "createSurface(): no matching configs were found, num_configs: " << num_configs;
+		return false;
+	}
+
+
+	// each attribute has 2 values, and we need one extra for the EGL_NONE terminator
+	EGLint attribute_list_window_surface[settings.windowSurfaceAttributes.size() * 2 + 1];
+
+	iter = settings.windowSurfaceAttributes.begin();
+	iterEnd = settings.windowSurfaceAttributes.end();
+
+	i = 0;
+	for(; iter != iterEnd; iter++) {
+		attribute_list_window_surface[i++] = iter->first;
+		attribute_list_window_surface[i++] = iter->second;
+	}
+	attribute_list_window_surface[i] = EGL_NONE; // add the terminator
+
+	// create a surface
+	eglSurface = eglCreateWindowSurface( eglDisplay, // our display handle
+			eglConfig,	// our first config
+			nativeWindow, // our native window
+			attribute_list_window_surface); // surface attribute list
+
+	if(eglSurface == EGL_NO_SURFACE) {
+		EGLint error = eglGetError();
+		switch(error) {
+		case EGL_BAD_MATCH:
+			ofLogError("ofAppEGLWindow") << "createSurface(): error creating surface: EGL_BAD_MATCH " << eglErrorString(error);
+			ofLogError("ofAppEGLWindow") << "createSurface(): check window and EGLConfig attributes to determine compatibility, ";
+			ofLogError("ofAppEGLWindow") << "createSurface(): or verify that the EGLConfig supports rendering to a window";
+			break;
+		case EGL_BAD_CONFIG:
+			ofLogError("ofAppEGLWindow") << "createSurface(): error creating surface: EGL_BAD_CONFIG " << eglErrorString(error);
+			ofLogError("ofAppEGLWindow") << "createSurface(): verify that provided EGLConfig is valid";
+			break;
+		case EGL_BAD_NATIVE_WINDOW:
+			ofLogError("ofAppEGLWindow") << "createSurface(): error creating surface: EGL_BAD_NATIVE_WINDOW " << eglErrorString(error);
+			ofLogError("ofAppEGLWindow") << "createSurface(): verify that provided EGLNativeWindow is valid";
+			break;
+		case EGL_BAD_ALLOC:
+			ofLogError("ofAppEGLWindow") << "createSurface(): error creating surface: EGL_BAD_ALLOC " << eglErrorString(error);
+			ofLogError("ofAppEGLWindow") << "createSurface(): not enough resources available";
+			break;
+		default:
+			ofLogError("ofAppEGLWindow") << "createSurface(): error creating surface: << " << error << eglErrorString(error);
+		}
+
+		return false;
+	}else{
+		ofLogNotice("ofAppEGLWindow") << "createSurface(): surface created correctly";
+	}
+
+	// get an appropriate EGL frame buffer configuration
+	result = eglBindAPI(EGL_OPENGL_ES_API);
+
+	if(result == EGL_FALSE) {
+		ofLogError("ofAppEGLWindow") << "createSurface(): error binding API: " << eglErrorString(eglGetError());
+		return false;
+	}else{
+		ofLogNotice("ofAppEGLWindow") << "createSurface(): API bound correctly";
+	}
+
+	// create an EGL rendering eglContext
+	EGLint attribute_list_surface_context[] = {
+			EGL_CONTEXT_CLIENT_VERSION, glesVersionForContext,
+			EGL_NONE
+	};
+
+	eglContext = eglCreateContext(eglDisplay,
+			eglConfig,
+			EGL_NO_CONTEXT,
+			attribute_list_surface_context);
+
+	if(eglContext == EGL_NO_CONTEXT) {
+		EGLint error = eglGetError();
+		if(error == EGL_BAD_CONFIG) {
+			ofLogError("ofAppEGLWindow") << "createSurface(): error creating context: EGL_BAD_CONFIG " << eglErrorString(error);
+			return false;
+		} else {
+			ofLogError("ofAppEGLWindow") << "createSurface(): error creating context: " << error << " " << eglErrorString(error);
+			return false;
+		}
+	}
+
+	// connect the eglContext to the eglSurface
+	result = eglMakeCurrent(eglDisplay,
+			eglSurface, // draw surface
+			eglSurface, // read surface
+			eglContext);
+
+	if(eglContext == EGL_FALSE) {
+		EGLint error = eglGetError();
+		ofLogError("ofAppEGLWindow") << "createSurface(): couldn't making current surface: " << eglErrorString(error);
+		return false;
+	}
+
+	// Set background color and clear buffers
+	glClearColor(settings.initialClearColor.r / 255.0f,
+			settings.initialClearColor.g / 255.0f,
+			settings.initialClearColor.b / 255.0f,
+			settings.initialClearColor.a / 255.0f);
+	glClear( GL_COLOR_BUFFER_BIT );
+	glClear( GL_DEPTH_BUFFER_BIT );
+
+	ofLogNotice("ofAppEGLWindow") << "createSurface(): -----EGL-----";
+	ofLogNotice("ofAppEGLWindow") << "createSurface(): EGL_VERSION_MAJOR = " << eglVersionMajor;
+	ofLogNotice("ofAppEGLWindow") << "createSurface(): EGL_VERSION_MINOR = " << eglVersionMinor;
+	ofLogNotice("ofAppEGLWindow") << "createSurface(): EGL_CLIENT_APIS = " << eglQueryString(eglDisplay, EGL_CLIENT_APIS);
+	ofLogNotice("ofAppEGLWindow") << "createSurface(): EGL_VENDOR = "  << eglQueryString(eglDisplay, EGL_VENDOR);
+	ofLogNotice("ofAppEGLWindow") << "createSurface(): EGL_VERSION = " << eglQueryString(eglDisplay, EGL_VERSION);
+	ofLogNotice("ofAppEGLWindow") << "createSurface(): EGL_EXTENSIONS = " << eglQueryString(eglDisplay, EGL_EXTENSIONS);
+	ofLogNotice("ofAppEGLWindow") << "createSurface(): GL_RENDERER = " << glGetString(GL_RENDERER);
+	ofLogNotice("ofAppEGLWindow") << "createSurface(): GL_VERSION  = " << glGetString(GL_VERSION);
+	ofLogNotice("ofAppEGLWindow") << "createSurface(): GL_VENDOR   = " << glGetString(GL_VENDOR);
+	ofLogNotice("ofAppEGLWindow") << "createSurface(): -------------";
+
+	isSurfaceInited = true;
+
+	return true;
+}
+
+//------------------------------------------------------------
+bool ofAppEGLWindow::destroySurface() {
+	if(isSurfaceInited) {
+		ofLogNotice("ofAppEGLWindow") << "destroySurface(): destroying EGL surface";
+		eglSwapBuffers(eglDisplay, eglSurface);
+		eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+		eglDestroySurface(eglDisplay, eglSurface);
+		eglDestroyContext(eglDisplay, eglContext);
+		eglTerminate(eglDisplay);
+		isSurfaceInited = false;
+
+		eglDisplay = NULL;
+		eglSurface = NULL;
+		eglContext = NULL;
+		eglConfig  = NULL;
+		eglVersionMinor = -1;
+		eglVersionMinor = -1;
+
+		return true;
+	} else {
+		ofLogError("ofAppEGLWindow") << "destroySurface(): attempted to destroy uninitialized window";
+		return false;
+	}
+}
+
+//------------------------------------------------------------
+bool ofAppEGLWindow::destroyWindow() {
+	if(isWindowInited) {
+		if(isUsingX11) {
+			// TODO: double check
+			XDestroyWindow(x11Display,x11Window); // or XCloseWindow?
+			XFree(x11Screen);
+		} else {
+#ifdef TARGET_RASPBERRY_PI
+			dispman_update = vc_dispmanx_update_start(0);
+			if (dispman_element != DISPMANX_NO_HANDLE) {
+				vc_dispmanx_element_remove(dispman_update, dispman_element);
+				dispman_element = DISPMANX_NO_HANDLE;
+			}
+
+			vc_dispmanx_update_submit_sync(dispman_update);
+
+			if (dispman_display != DISPMANX_NO_HANDLE) {
+				vc_dispmanx_display_close(dispman_display);
+				dispman_display = DISPMANX_NO_HANDLE;
+			}
+#else
+	ofLogNotice("ofAppEGLWindow") << "destroyWindow(): no native window type for this system, perhaps try X11?";
+#endif
+		}
+
+	} else {
+		ofLogNotice("ofAppEGLWindow") << "destroyWindow(): destroying (uninited) native window (not implemented yet)";
+	}
+
+	return true;
+}
+
+
+void ofAppEGLWindow::close(){
+	if(!isUsingX11) {
+		destroyNativeEvents();
+	}
+
+	// we got a terminate ... so clean up.
+	destroySurface();
+	destroyWindow();
+
+	exitNative();
+	events().notifyExit();
+	events().disable();
+}
+
+//------------------------------------------------------------
+void ofAppEGLWindow::makeCurrent(){
+	eglMakeCurrent(eglDisplay,
+			eglSurface, // draw surface
+			eglSurface, // read surface
+			eglContext);
+}
+
+//------------------------------------------------------------
+void ofAppEGLWindow::swapBuffers(){
+	EGLBoolean success = eglSwapBuffers(eglDisplay, eglSurface);
+	if(!success) {
+		GLint error = eglGetError();
+		ofLogNotice("ofAppEGLWindow") << "display(): eglSwapBuffers failed: " << eglErrorString(error);
+	}
+}
+
+//--------------------------------------------
+void ofAppEGLWindow::startRender() {
+	renderer()->startRender();
+}
+
+//--------------------------------------------
+void ofAppEGLWindow::finishRender() {
+	renderer()->finishRender();
+}
+
+//------------------------------------------------------------
+void ofAppEGLWindow::update() {
+	coreEvents.notifyUpdate();
+}
+
+
+//------------------------------------------------------------
+void ofAppEGLWindow::draw() {
+	// take care of any requests for a new screen mode
+	if (windowMode != OF_GAME_MODE && bNewScreenMode){
+		if( windowMode == OF_FULLSCREEN){
+			setWindowRect(getScreenRect());
+		} else if( windowMode == OF_WINDOW ){
+			setWindowRect(nonFullscreenWindowRect);
+		}
+		bNewScreenMode = false;
+	}
+
+	currentRenderer->startRender();
+	if( bEnableSetupScreen ) currentRenderer->setupScreen();
+
+	coreEvents.notifyDraw();
+
+	if(!isUsingX11) {
+		if(bShowCursor){
+			GLboolean bIsDepthTestEnabled = GL_FALSE;
+			glGetBooleanv(GL_DEPTH_TEST, &bIsDepthTestEnabled);
+
+			if(bIsDepthTestEnabled == GL_TRUE) {
+				glDisable(GL_DEPTH_TEST);
+			}
+
+			bool isUsingNormalizedTexCoords = ofGetUsingNormalizedTexCoords();
+			if(isUsingNormalizedTexCoords) {
+				ofDisableNormalizedTexCoords();
+			}
+
+			currentRenderer->pushStyle();
+			currentRenderer->setBlendMode(OF_BLENDMODE_ADD);
+			currentRenderer->setColor(255);
+			mouseCursor.draw(ofGetMouseX(),ofGetMouseY());
+
+			currentRenderer->popStyle();
+
+			if(bIsDepthTestEnabled == GL_TRUE) {
+				glEnable(GL_DEPTH_TEST);
+			}
+
+			if(isUsingNormalizedTexCoords) {
+				ofEnableNormalizedTexCoords();
+			}
+		}
+	}
+	currentRenderer->finishRender();
+
+	EGLBoolean success = eglSwapBuffers(eglDisplay, eglSurface);
+	if(!success) {
+		GLint error = eglGetError();
+		ofLogNotice("ofAppEGLWindow") << "display(): eglSwapBuffers failed: " << eglErrorString(error);
+	}
+
+	nFramesSinceWindowResized++;
+
+}
+
+//------------------------------------------------------------
+ofCoreEvents & ofAppEGLWindow::events(){
+	return coreEvents;
+}
+
+//------------------------------------------------------------
+shared_ptr<ofBaseRenderer> & ofAppEGLWindow::renderer(){
+	return currentRenderer;
+}
+
+//------------------------------------------------------------
+void ofAppEGLWindow::setupNativeEvents() {
+	setupNativeUDev();
+	setupNativeMouse();
+	setupNativeKeyboard();
+	startThread();
+}
+
+//------------------------------------------------------------
+void ofAppEGLWindow::destroyNativeEvents() {
+	destroyNativeUDev();
+	destroyNativeMouse();
+	destroyNativeKeyboard();
+	waitForThread(true, threadTimeout);
+}
+
+//------------------------------------------------------------
+void ofAppEGLWindow::setWindowRect(const ofRectangle& requestedWindowRect) {
+	if(!isWindowInited) {
+		ofLogError("ofAppEGLWindow") << "setWindowRect(): window not inited";
+		return;
+	}
+
+	ofRectangle newRect = requestedWindowRect.getStandardized();
+
+	if(newRect != currentWindowRect) {
+		ofRectangle oldWindowRect = currentWindowRect;
+
+		if(isUsingX11) {
+			int ret = XMoveResizeWindow(x11Display,
+					x11Window,
+					(int)newRect.x,
+					(int)newRect.y,
+					(unsigned int)newRect.width,
+					(unsigned int)newRect.height);
+			if(ret == BadValue) {
+				ofLogError("ofAppEGLWindow") << "setWindowRect(): XMoveResizeWindow returned BadValue";
+			} else if(ret == BadWindow) {
+				ofLogError("ofAppEGLWindow") << "setWindowRect(): XMoveResizeWindow returned BadWindow";
+			} else {
+				// all is good
+				currentWindowRect = newRect;
+			}
+		} else {
+#ifdef TARGET_RASPBERRY_PI
+
+			VC_RECT_T dst_rect;
+			dst_rect.x = (int32_t)newRect.x;
+			dst_rect.y = (int32_t)newRect.y;
+			dst_rect.width = (int32_t)newRect.width;
+			dst_rect.height = (int32_t)newRect.height;
+
+			VC_RECT_T src_rect;
+			src_rect.x = 0;
+			src_rect.y = 0;
+			src_rect.width = (int32_t)newRect.width << 16;
+			src_rect.height = (int32_t)newRect.height << 16;
+
+			DISPMANX_UPDATE_HANDLE_T dispman_update = vc_dispmanx_update_start(0);
+
+			vc_dispmanx_element_change_attributes(dispman_update,
+					dispman_element,
+					ELEMENT_CHANGE_SRC_RECT|ELEMENT_CHANGE_DEST_RECT, // we do both when resizing
+					0, // layer (we aren't changing it here)
+					0, // opactiy (we aren't changing it here)
+					&dst_rect,
+					&src_rect,
+					0, // mask (we aren't changing it here)
+					(DISPMANX_TRANSFORM_T)0);
+
+
+			vc_dispmanx_update_submit_sync(dispman_update);
+
+			// next time swapBuffers is called, it will be resized based on this eglwindow size data
+			dispman_native_window.element = dispman_element;
+			dispman_native_window.width = (int32_t)newRect.width;
+			dispman_native_window.height = (int32_t)newRect.height; // don't forget!
+
+			currentWindowRect = newRect;
+
+#else
+			ofLogError("ofAppEGLWindow") << "createEGLWindow(): no native window type for this system, perhaps try X11?";
+#endif
+		}
+
+		if(oldWindowRect.width  != currentWindowRect.width || oldWindowRect.height != currentWindowRect.height) {
+			coreEvents.notifyWindowResized(currentWindowRect.width,	currentWindowRect.height);
+			nFramesSinceWindowResized = 0;
+		}
+	}
+}
+
+
+//------------------------------------------------------------
+bool ofAppEGLWindow::createWindow(const ofRectangle& requestedWindowRect) {
+	if(isUsingX11) {
+		return createX11NativeWindow(requestedWindowRect);
+	} else {
+#ifdef TARGET_RASPBERRY_PI
+		return createRPiNativeWindow(requestedWindowRect);
+#else
+		ofLogError("ofAppEGLWindow") << "createEGLWindow(): no native window type for this system, perhaps try X11?";
+		return false;
+#endif
+	}
+}
+
+//------------------------------------------------------------
+int ofAppEGLWindow::getWindowWidth() {
+	return currentWindowRect.width;
+}
+
+//------------------------------------------------------------
+int ofAppEGLWindow::getWindowHeight() {
+	return currentWindowRect.height;
+}
+
+//------------------------------------------------------------
+void ofAppEGLWindow::pollEvents(){
+	if(!instance) return;
+	if(instance->isUsingX11) {
+		while(1){
+			XEvent event;
+			if (::XCheckWindowEvent(instance->x11Display, instance->x11Window, -1, &event)){
+				handleX11Event(event);
+			}else if (::XCheckTypedEvent(instance->x11Display, ClientMessage, &event)){
+				handleX11Event(event);
+			}else{
+				break;
+			}
+		}
+	} else {
+		queue<ofMouseEventArgs> mouseEventsCopy;
+		instance->lock();
+		mouseEventsCopy = instance->mouseEvents;
+		while(!instance->mouseEvents.empty()){
+			instance->mouseEvents.pop();
+		}
+		instance->unlock();
+		while(!mouseEventsCopy.empty()){
+			instance->coreEvents.notifyMouseEvent(mouseEventsCopy.front());
+			mouseEventsCopy.pop();
+		}
+
+		// KEYBOARD EVENTS
+		queue<ofKeyEventArgs> keyEventsCopy;
+		instance->lock();
+		keyEventsCopy = instance->keyEvents;
+		while(!instance->keyEvents.empty()){
+			instance->keyEvents.pop();
+		}
+		instance->unlock();
+		while(!keyEventsCopy.empty()){
+			instance->coreEvents.notifyKeyEvent(keyEventsCopy.front());
+			keyEventsCopy.pop();
+		}
+	}
+}
+
+//------------------------------------------------------------
+void ofAppEGLWindow::hideCursor(){
+	bShowCursor = false;
+}
+
+//------------------------------------------------------------
+void ofAppEGLWindow::showCursor(){
+	bShowCursor = true;
+}
+
+//------------------------------------------------------------
+void ofAppEGLWindow::setWindowTitle(string title) {
+	ofLogNotice("ofAppEGLWindow") << "setWindowTitle(): not implemented";
+}
+
+//------------------------------------------------------------
+glm::vec2 ofAppEGLWindow::getWindowSize(){
+	return {currentWindowRect.width, currentWindowRect.height};
+}
+
+//------------------------------------------------------------
+glm::vec2 ofAppEGLWindow::getWindowPosition(){
+	return currentWindowRect.getPosition().xy();
+}
+
+//------------------------------------------------------------
+glm::vec2 ofAppEGLWindow::getScreenSize(){
+	unsigned int screenWidth = 0;
+	unsigned int screenHeight = 0;
+
+	if(isUsingX11) {
+		// TODO, there must be a way to get screensize if the window is not inited
+		if(isWindowInited && x11Screen) {
+			screenWidth  = XWidthOfScreen(x11Screen);
+			screenHeight = XHeightOfScreen(x11Screen);
+		} else {
+			ofLogError("ofAppEGLWindow") << "getScreenSize(): tried to get display size but failed, x11Screen is not inited";
+		}
+
+	} else {
+#ifdef TARGET_RASPBERRY_PI
+		int success = graphics_get_display_size(settings.screenNum, &screenWidth, &screenHeight);
+		if(success < 0) {
+			ofLogError("ofAppEGLWindow") << "getScreenSize(): tried to get display size but failed";
+		}
+
+#else
+		ofLogError("ofAppEGLWindow") << "getScreenSize(): no native window type for this system, perhaps try X11?";
+#endif
+
+	}
+
+	return {screenWidth, screenHeight};
+}
+
+//------------------------------------------------------------
+int ofAppEGLWindow::getWidth(){
+	if( orientation == OF_ORIENTATION_DEFAULT || orientation == OF_ORIENTATION_180 ){
+		return currentWindowRect.width;
+	}
+	return currentWindowRect.height;
+}
+
+//------------------------------------------------------------
+int ofAppEGLWindow::getHeight(){
+	if( orientation == OF_ORIENTATION_DEFAULT || orientation == OF_ORIENTATION_180 ){
+		return currentWindowRect.height;
+	}
+	return currentWindowRect.width;
+}
+
+//------------------------------------------------------------
+void ofAppEGLWindow::setOrientation(ofOrientation orientationIn){
+	orientation = orientationIn;
+}
+
+//------------------------------------------------------------
+ofOrientation ofAppEGLWindow::getOrientation(){
+	return orientation;
+}
+
+//------------------------------------------------------------
+bool ofAppEGLWindow::doesHWOrientation() {
+	return false;
+}
+
+//------------------------------------------------------------
+void ofAppEGLWindow::setWindowPosition(int x, int y){
+	if(!isWindowInited) {
+		ofLogError("ofAppEGLWindow") << "setWindowPosition(): window not inited";
+		return;
+	}
+
+	if(isUsingX11) {
+		int ret = XMoveWindow(x11Display,
+				x11Window,
+				x,
+				y);
+		if(ret == BadValue) {
+			ofLogError("ofAppEGLWindow") << "setWindowPosition(): XMoveWindow returned BadValue";
+		} else if(ret == BadWindow) {
+			ofLogError("ofAppEGLWindow") << "setWindowPosition(): XMoveWindow returned BadWindow";
+		} else {
+			currentWindowRect.x = x;
+			currentWindowRect.y = y;
+			nonFullscreenWindowRect = currentWindowRect;
+		}
+	} else {
+#ifdef TARGET_RASPBERRY_PI
+
+		// keep it in bounds
+		auto screenSize = getScreenSize();
+		x = ofClamp(x, 0, screenSize.x - currentWindowRect.width);
+		y = ofClamp(y, 0, screenSize.y - currentWindowRect.height);
+
+		VC_RECT_T dst_rect;
+		dst_rect.x = (int32_t)x;
+		dst_rect.y = (int32_t)y;
+		dst_rect.width = (int32_t)currentWindowRect.width;
+		dst_rect.height = (int32_t)currentWindowRect.height;
+
+		dispman_update = vc_dispmanx_update_start(0);
+
+		vc_dispmanx_element_change_attributes(dispman_update,
+				dispman_native_window.element,
+				ELEMENT_CHANGE_DEST_RECT,
+				0,
+				0,
+				&dst_rect,
+				NULL,
+				0,
+				(DISPMANX_TRANSFORM_T)0);
+
+
+vc_dispmanx_update_submit_sync(dispman_update);
+
+currentWindowRect.x = x;
+currentWindowRect.y = y;
+nonFullscreenWindowRect = currentWindowRect;
+
+#else
+	ofLogError("ofAppEGLWindow") << "setWindowPosition(): no native window type for this system, perhaps try X11?";
+#endif
+	}
+
+}
+
+//------------------------------------------------------------
+void ofAppEGLWindow::setWindowShape(int w, int h){
+	if(!isWindowInited) {
+		ofLogError("ofAppEGLWindow") << "setWindowPosition(): window not inited";
+		return;
+	}
+
+	if(isUsingX11) {
+		int ret = XResizeWindow(x11Display,
+				x11Window,
+				(unsigned int)w,
+				(unsigned int)h);
+		if(ret == BadValue) {
+			ofLogError("ofAppEGLWindow") << "setWindowPosition(): XMoveWindow returned BadValue";
+		} else if(ret == BadWindow) {
+			ofLogError("ofAppEGLWindow") << "setWindowPosition(): XMoveWindow returned BadWindow";
+		} else {
+			currentWindowRect.width = w;
+			currentWindowRect.height = h;
+			nonFullscreenWindowRect = currentWindowRect;
+		}
+	} else {
+#ifdef TARGET_RASPBERRY_PI
+		setWindowRect(ofRectangle(currentWindowRect.x,currentWindowRect.y,w,h));
+		nonFullscreenWindowRect = currentWindowRect;
+#else
+		ofLogError("ofAppEGLWindow") << "setWindowPosition(): no native window type for this system, perhaps try X11?";
+#endif
+	}
+}
+
+//------------------------------------------------------------
+ofWindowMode ofAppEGLWindow::getWindowMode(){
+	return windowMode;
+}
+
+//------------------------------------------------------------
+void ofAppEGLWindow::toggleFullscreen(){
+	if( windowMode == OF_GAME_MODE) return;
+
+	if( windowMode == OF_WINDOW ){
+		setFullscreen(true);
+	}else{
+		setFullscreen(false);
+	}
+
+}
+
+//------------------------------------------------------------
+void ofAppEGLWindow::setFullscreen(bool fullscreen){
+	if( windowMode == OF_GAME_MODE) return;
+
+	if(fullscreen && windowMode != OF_FULLSCREEN){
+		bNewScreenMode = true;
+		windowMode = OF_FULLSCREEN;
+	}else if(!fullscreen && windowMode != OF_WINDOW) {
+		bNewScreenMode = true;
+		windowMode = OF_WINDOW;
+	}
+}
+
+//------------------------------------------------------------
+void ofAppEGLWindow::enableSetupScreen(){
+	bEnableSetupScreen = true;
+}
+
+//------------------------------------------------------------
+void ofAppEGLWindow::disableSetupScreen(){
+	bEnableSetupScreen = false;
+}
+
+//------------------------------------------------------------
+ofRectangle ofAppEGLWindow::getScreenRect(){
+	auto screenSize = getScreenSize();
+	return ofRectangle(0,0,screenSize.x,screenSize.y);
+}
+
+//------------------------------------------------------------
+void ofAppEGLWindow::setVerticalSync(bool enabled){
+	eglSwapInterval(eglDisplay, enabled ? 1 : 0);
+}
+
+//------------------------------------------------------------
+void ofAppEGLWindow::threadedFunction(){
+	// TODO: a way to setup mouse and keyboard if
+	// they are not plugged in upon start
+	// This can be done with our udev device callbacks
+
+	while(isThreadRunning()) {
+		readNativeUDevEvents();
+		readNativeMouseEvents();
+		readNativeKeyboardEvents();
+
+		// sleep briefly
+		ofSleepMillis(20);
+	}
+}
+
+//------------------------------------------------------------
+// PLATFORM SPECIFIC RPI
+//------------------------------------------------------------
+
+//------------------------------------------------------------
+void ofAppEGLWindow::setupNativeUDev() {
+
+	udev = udev_new(); // create new udev object
+	if(!udev) {
+		ofLogError("ofAppEGLWindow") << "setupNativeUDev(): couldn't create udev object";
+	} else {
+		ofLogNotice("ofAppEGLWindow") << "setupNativeUDev(): created udev object";
+		// setup udev to monitor for input devices
+		mon = udev_monitor_new_from_netlink(udev, "udev");
+		// just listen for input devices
+		udev_monitor_filter_add_match_subsystem_devtype(mon, "input", NULL);
+		udev_monitor_enable_receiving(mon);
+		// get the file descriptor for the mon (used w/ select);
+		udev_fd = udev_monitor_get_fd(mon);
+	}
+
+	if(udev_fd < 0) {
+		ofLogError("ofAppEGLWindow") << "setupNativeUDev(): did not create udev object, udev_fd < 0";
+	}
+
+}
+
+//------------------------------------------------------------
+void ofAppEGLWindow::destroyNativeUDev() {
+	udev_unref(udev); // clean up
+}
+
+
+//------------------------------------------------------------
+void ofAppEGLWindow::setupNativeMouse() {
+	struct dirent **eps; // What eps is supposed to mean? 
+
+	// fallback to /dev/input/eventX since some vnc servers use uinput to 
+	// handle mouse & keyboard.
+	typedef int (*filter_ptr)(const struct dirent *d);
+	filter_ptr mouse_filters[2] = { filter_mouse, filter_event };
+	string devicePathBuffers[2] = { "/dev/input/by-path/", "/dev/input/" };
+
+	// Examine available input devices in directories at devicePathBuffers.
+	for(auto i = 0; i < 2; i++){
+		
+		// Get number of devices in the current input device directory.
+		int n = scandir(devicePathBuffers[i].c_str(), &eps, mouse_filters[i], dummy_sort);
+
+		// Open the appropriate entries, 
+		// we want to get all mouse device events.
+		if(n >= 0 && eps != 0 && eps[0] != 0) {
+			for(auto j = 0; j < n; ++j){
+				string devicePathBuffer;
+				devicePathBuffer.append(devicePathBuffers[i]);
+				devicePathBuffer.append(eps[j]->d_name);
+				
+				ofLogNotice("ofAppEGLWindow::setupNativeMouse()")
+					<< "attempt to open " << devicePathBuffer;
+
+				// TODO: create a vector out of fildes entries
+				int fildes = open(devicePathBuffer.c_str(), O_RDONLY | O_NONBLOCK);
+
+				// No file descriptor, stop the current iteration of the nested loop here,
+				// continue with the next value of j.
+				if(fildes < 0){
+					ofLogError("ofAppEGLWindow::setupNativeMouse()") 
+						<< "failed to open mouse device";
+					continue;
+				}
+
+				// Seems that we got a mouse device open! 
+				// Get all the parameters.
+				ofAppEGLWindowMouseArgs mouseArgs;
+				mouseArgs.fildes = fildes;
+
+				// TODO: consider a more reasonable way for calculating these.
+				mouseArgs.scaleX = 2.0f;
+				mouseArgs.scaleY = 2.0f;
+
+				// Find out if input device is a absolute positioning device
+				// set the minimum and maximum values of the axes.
+				// Do this for the x axis. EVIOCGABS(0): 0 stands for x axis.
+				struct input_absinfo mabsx;
+				if (ioctl(fildes, EVIOCGABS(0), &mabsx) < 0){
+					ofLogError("ofAppEGLWindow::setupNativeMouse()") 
+						<< "failed to get absolute limits of input x axis";
+					mouseArgs.absXMin = 0;
+					mouseArgs.absXMax = 0;
+				} else {
+					mouseArgs.absXMin = mabsx.minimum;
+					mouseArgs.absXMax = mabsx.maximum;
+					ofLogNotice("ofAppEGLWindow::setupNativeMouse()") 
+						<< "mouse x axis min, max: " << mouseArgs.absXMin 
+						<< ", " << mouseArgs.absXMax;
+				}
+				
+				// Do that for the y axis. EVIOCGABS(1): 1 stands for y axis.
+				struct input_absinfo mabsy;
+				if (ioctl(fildes, EVIOCGABS(1), &mabsy) < 0){
+					ofLogError("ofAppEGLWindow::setupNativeMouse()") 
+						<< "failed to get absolute limits of input y axis";
+					mouseArgs.absYMin = 0;
+					mouseArgs.absYMax = 0;
+				} else {
+					mouseArgs.absYMin = mabsy.minimum;
+					mouseArgs.absYMax = mabsy.maximum;
+					ofLogNotice("ofAppEGLWindow::setupNativeMouse()") 
+						<< "mouse y axis min, max: " << mouseArgs.absYMin 
+						<< ", " << mouseArgs.absYMax;
+				}
+
+				// Get input device name.
+				char deviceNameBuffer[256] = "Unknown Device";
+				ioctl(fildes, EVIOCGNAME(sizeof(deviceNameBuffer)), deviceNameBuffer);
+				mouseArgs.deviceName = string(deviceNameBuffer);
+				ofLogNotice("ofAppEGLWindow::setupNativeMouse()") 
+					<< "setting up mouse device with name " 
+					<< mouseArgs.deviceName;
+
+				mice.push_back(mouseArgs);
+
+				ofLogNotice("ofAppEGLWindow") << "setupMouse(): fildes=" 
+					<<  fildes << " devicePath=" << devicePathBuffer;
+			} // Nested for loop
+		}
+
+		// Do not examine other input device directories if we found some mice here.
+		// This breaks the main for loop of setupNativeMouse().
+		if(mice.size()){
+			break;
+		}
+	} // Main for loop
+
+	mb.mouseButtonState = 0;
+
+	if(mice.size() <= 0) {
+		mouseDetected = false;
+		ofLogWrning("ofAppEGLWindow::setupNativeMouse()") 
+			<< "no mouse found";
+	} else {
+		mouseDetected = true;
+	}
+}
+
+//------------------------------------------------------------
+void ofAppEGLWindow::setupNativeKeyboard() {
+	struct dirent **eps;
+	typedef int (*filter_ptr)(const struct dirent *d);
+	filter_ptr kbd_filters[2] = { filter_kbd, filter_event };
+	string devicePathBuffers[2] = { "/dev/input/by-path/", "/dev/input/" };
+
+	for(int i=0; i<2; i++){
+		int n = scandir(devicePathBuffers[i].c_str(), &eps, kbd_filters[i], dummy_sort);
+
+		// make sure that we found an appropriate entry
+		if(n >= 0 && eps != 0 && eps[0] != 0) {
+			string devicePathBuffer;
+			devicePathBuffer.append(devicePathBuffers[i]);
+			devicePathBuffer.append(eps[0]->d_name);
+			keyboard_fd = open(devicePathBuffer.c_str(), O_RDONLY | O_NONBLOCK);
+			ofLogNotice("ofAppEGLWindow") << "setupKeyboard(): keyboard_fd=" <<  keyboard_fd << " devicePath=" << devicePathBuffer;
+			break;
+		}
+	}
+
+	if (keyboard_fd >= 0) {
+		char deviceNameBuffer[256] = "Unknown Device";
+		ioctl(keyboard_fd, EVIOCGNAME(sizeof(deviceNameBuffer)), deviceNameBuffer);
+		ofLogNotice("ofAppEGLWindow") << "setupKeyboard(): keyboard device name = " << deviceNameBuffer;
+
+
+		// save current terminal settings
+		tcgetattr (STDIN_FILENO, &tc);
+		ots = tc;
+		// disable echo on our temporary settings
+		tc.c_lflag &= ~ECHO;
+		tc.c_lflag |= ECHONL;
+		tcsetattr(STDIN_FILENO, TCSAFLUSH, &tc);
+
+	} else {
+		ofLogError("ofAppEGLWindow") << "setupKeyboard(): did not open keyboard";
+	}
+
+	kb.shiftPressed = false;
+	kb.capsLocked = false;
+
+	if(keyboard_fd < 0) {
+		ofLogError("ofAppEGLWindow") << "setupKeyboard(): did not open keyboard, keyboard_fd < 0";
+	} else {
+		keyboardDetected = true;
+	}
+}
+
+//------------------------------------------------------------
+void ofAppEGLWindow::destroyNativeMouse() {
+	for(auto i = 0; i < mice.size(); ++i){
+		int retval = close(mice[i].fildes);
+		if(retval < 0){
+			ofLogError("ofAppEGLWindow::destroyNativeMouse()") 
+				<< "Failed to close mouse device: "
+				<< mice[i].deviceName;
+		}
+	}
+	mice.clear();
+}
+
+//------------------------------------------------------------
+void ofAppEGLWindow::destroyNativeKeyboard() {
+	ofLogNotice("ofAppEGLWindow") << "destroyNativeKeyboard()";
+
+	if (keyboard_fd >= 0) {
+		tcsetattr (STDIN_FILENO, TCSAFLUSH, &ots);
+	} else {
+		ofLogNotice("ofAppEGLWindow") << "destroyNativeKeyboard(): unable to reset terminal";
+	}
+}
+
+
+//------------------------------------------------------------
+void ofAppEGLWindow::readNativeUDevEvents() {
+	// look for devices being attatched / detatched
+
+	fd_set fds;
+	struct timeval tv;
+	int ret;
+
+	FD_ZERO(&fds);
+	FD_SET(udev_fd, &fds);
+	tv.tv_sec = 0;
+	tv.tv_usec = 0;
+
+	ret = select(udev_fd+1, &fds, NULL, NULL, &tv);
+
+	/* Check if our file descriptor has received data. */
+	if (ret > 0 && FD_ISSET(udev_fd, &fds)) {
+		/* Make the call to receive the device.
+		   select() ensured that this will not block. */
+		dev = udev_monitor_receive_device(mon);
+		if (dev) {
+			// TODO: finish auto connect
+			ofLogNotice() << "Got device";
+			ofLogNotice() << "   node: %s\n", udev_device_get_devnode(dev);
+			ofLogNotice() << "   subsystem: %s\n", udev_device_get_subsystem(dev);
+			ofLogNotice() << "   devtype: %s\n", udev_device_get_devtype(dev);
+			ofLogNotice() << "   action: %s\n", udev_device_get_action(dev);
+			udev_device_unref(dev);
+		}
+		else {
+			ofLogNotice("ofAppEGLWindow") << "readNativeUDevEvents(): device returned by receive_device() is NULL";
+		}
+	}
+}
+
+//------------------------------------------------------------
+void ofAppEGLWindow::readNativeKeyboardEvents() {
+	// http://www.diegm.uniud.it/loghi/CE2/kbd.pdf
+	// http://cgit.freedesktop.org/~whot/evtest/plain/evtest.c
+	// https://strcpy.net/b/archives/2010/11/17/abusing_the_linux_input_subsystem/index.html
+	struct input_event ev;
+	char key = 0;
+
+	int nBytesRead = read(keyboard_fd, &ev,sizeof(struct input_event));
+
+	static ofKeyEventArgs keyEvent;
+	bool pushKeyEvent = false;
+
+	while(nBytesRead >= 0) {
+
+		if (ev.type==EV_KEY) {
+			if(ev.value == 0) {
+				// key released
+				keyEvent.type = ofKeyEventArgs::Released;
+			} else if(ev.value == 1) {
+				// key pressed
+				keyEvent.type = ofKeyEventArgs::Pressed;
+			} else if(ev.value == 2) {
+				// key repeated
+				keyEvent.type = ofKeyEventArgs::Pressed;
+			} else {
+				// unknown ev.value
+			}
+
+			switch (ev.code) {
+			case KEY_RIGHTSHIFT:
+			case KEY_LEFTSHIFT:
+				kb.shiftPressed = ev.value;
+				break;
+			case KEY_RIGHTCTRL:
+			case KEY_LEFTCTRL:
+				break;
+			case KEY_CAPSLOCK:
+				if (ev.value == 1) {
+					if (kb.capsLocked) {
+						kb.capsLocked = 0;
+					} else {
+						kb.capsLocked = 1;
+					}
+				}
+				break;
+
+			case KEY_ESC:
+				pushKeyEvent = true;
+				keyEvent.key = OF_KEY_ESC;
+				break;
+			case KEY_BACKSPACE:
+				pushKeyEvent = true;
+				keyEvent.key = OF_KEY_BACKSPACE;
+				break;
+			case KEY_DELETE:
+				pushKeyEvent = true;
+				keyEvent.key = OF_KEY_DEL;
+				break;
+			case KEY_F1:
+				pushKeyEvent = true;
+				keyEvent.key = OF_KEY_F1;
+				break;
+			case KEY_F2:
+				pushKeyEvent = true;
+				keyEvent.key = OF_KEY_F2;
+				break;
+			case KEY_F3:
+				pushKeyEvent = true;
+				keyEvent.key = OF_KEY_F3;
+				break;
+			case KEY_F4:
+				pushKeyEvent = true;
+				keyEvent.key = OF_KEY_F4;
+				break;
+			case KEY_F5:
+				pushKeyEvent = true;
+				keyEvent.key = OF_KEY_F5;
+				break;
+			case KEY_F6:
+				pushKeyEvent = true;
+				keyEvent.key = OF_KEY_F6;
+				break;
+			case KEY_F7:
+				pushKeyEvent = true;
+				keyEvent.key = OF_KEY_F7;
+				break;
+			case KEY_F8:
+				pushKeyEvent = true;
+				keyEvent.key = OF_KEY_F8;
+				break;
+			case KEY_F9:
+				pushKeyEvent = true;
+				keyEvent.key = OF_KEY_F9;
+				break;
+			case KEY_F10:
+				pushKeyEvent = true;
+				keyEvent.key = OF_KEY_F10;
+				break;
+			case KEY_F11:
+				pushKeyEvent = true;
+				keyEvent.key = OF_KEY_F11;
+				break;
+			case KEY_F12:
+				pushKeyEvent = true;
+				keyEvent.key = OF_KEY_F12;
+				break;
+			case KEY_LEFT:
+				pushKeyEvent = true;
+				keyEvent.key = OF_KEY_LEFT;
+				break;
+			case KEY_UP:
+				pushKeyEvent = true;
+				keyEvent.key = OF_KEY_UP;
+				break;
+			case KEY_RIGHT:
+				pushKeyEvent = true;
+				keyEvent.key = OF_KEY_RIGHT;
+				break;
+			case KEY_DOWN:
+				pushKeyEvent = true;
+				keyEvent.key = OF_KEY_DOWN;
+				break;
+			case KEY_PAGEUP:
+				pushKeyEvent = true;
+				keyEvent.key = OF_KEY_PAGE_UP;
+				break;
+			case KEY_PAGEDOWN:
+				pushKeyEvent = true;
+				keyEvent.key = OF_KEY_PAGE_DOWN;
+				break;
+			case KEY_HOME:
+				pushKeyEvent = true;
+				keyEvent.key = OF_KEY_HOME;
+				break;
+			case KEY_END:
+				pushKeyEvent = true;
+				keyEvent.key = OF_KEY_END;
+				break;
+			case KEY_INSERT:
+				pushKeyEvent = true;
+				keyEvent.key = OF_KEY_INSERT;
+				break;
+			case KEY_ENTER:
+			case KEY_KPENTER:
+				pushKeyEvent = true;
+				keyEvent.key = OF_KEY_RETURN;
+				break;
+
+			default:
+				// VERY RUDIMENTARY KEY MAPPING WITH MAPS ABOVE
+				if(ev.code < sizeof(lowercase_map)) {
+					if (kb.shiftPressed) {
+						key = uppercase_map[ev.code];
+						if (kb.capsLocked) keyEvent.key = tolower(key);
+						keyEvent.key = key;
+						pushKeyEvent = true;
+					} else {
+						key = lowercase_map[ev.code];
+						if (kb.capsLocked) key = toupper(key);
+						keyEvent.key = key;
+						pushKeyEvent = true;
+					}
+				} else {
+					ofLogNotice("ofAppEGLWindow") << "readKeyboardEvents(): input_event.code is outside of our small range";
+				}
+			}
+		} else if(ev.type == EV_MSC) {
+			// EV_MSC events are used for input and output events that
+			// do not fall under other categories.
+			// ofLogVerbose("ofAppEGLWindow") << "readKeyboardEvents(): EV_MSC";
+		} else if(ev.type == EV_SYN ) {
+			// EV_SYN Used as markers to separate events. Events may be
+			// separated in time or in space, such as with the multitouch protocol.
+			// ofLogVerbose("ofAppEGLWindow") << "readKeyboardEvents(): EV_SYN";
+		} else {
+			// unhandled type
+		}
+
+		// do we have a mouse svent to push?
+		if(pushKeyEvent){
+			lock();
+			keyEvents.push(keyEvent);
+			unlock();
+			pushKeyEvent = false;
+		}
+
+		nBytesRead = read(keyboard_fd, &ev,sizeof(struct input_event));
+	}
+}
+
+//------------------------------------------------------------
+void ofAppEGLWindow::readNativeMouseEvents() {
+	// http://cgit.freedesktop.org/~whot/evtest/plain/evtest.c
+	struct input_event ev;
+	static ofMouseEventArgs mouseEvent;
+	bool pushMouseEvent = false;
+
+	for(auto i = 0; i < mice.size(); ++i){
+		// Loop through all open mouse devices
+
+// -------------
+	int nBytesRead = read(mice[i].fildes, &ev,sizeof(struct input_event));
+
+	bool axisValuePending = false;
+
+	while(nBytesRead >= 0) {
+
+		if(ev.type == EV_REL || ev.type == EV_ABS) {
+			int axis = ev.code;
+			int amount = ev.value;
+
+			switch(axis) {
+			case 0:
+				if(ev.type == EV_REL) {
+					mouseEvent.x += amount * mouseScaleX;
+				} else {
+					mouseEvent.x = amount * (float)currentWindowRect.width / (float)mouseAbsXMax;
+				}
+
+				mouseEvent.x = ofClamp(mouseEvent.x, 0, currentWindowRect.width);
+				axisValuePending = true;
+				break;
+			case 1:
+				if(ev.type == EV_REL) {
+					mouseEvent.y += amount * mouseScaleY;
+				} else {
+					mouseEvent.y = amount * (float)currentWindowRect.height / (float)mouseAbsYMax;
+				}
+
+				mouseEvent.y = ofClamp(mouseEvent.y, 0, currentWindowRect.height);
+				axisValuePending = true;
+				break;
+			default:
+				ofLogNotice("ofAppEGLWindow") << "readMouseEvents(): unknown mouse axis (perhaps it's the scroll wheel?)";
+				break;
+			}
+
+		} else if(ev.type == EV_KEY) {
+			// only tracking three buttons now ...
+			if(ev.code == BTN_LEFT) {
+				if(ev.value == 0) { // release
+					mouseEvent.button = OF_MOUSE_BUTTON_LEFT;
+				mouseEvent.type = ofMouseEventArgs::Released;
+				mb.mouseButtonState &= ~MOUSE_BUTTON_LEFT_MASK;
+				pushMouseEvent = true;
+				} else if(ev.value == 1) { // press
+					mb.mouseButtonState |= MOUSE_BUTTON_LEFT_MASK;
+					mouseEvent.type = ofMouseEventArgs::Pressed;
+					mouseEvent.button = OF_MOUSE_BUTTON_LEFT;
+					pushMouseEvent = true;
+				} else { // unknown
+					ofLogNotice("ofAppEGLWindow") << "readMouseEvents(): EV_KEY : unknown ev.value = " << ev.value;
+				}
+			} else if(ev.code == BTN_MIDDLE) {
+				if(ev.value == 0) { // release
+					mouseEvent.button = OF_MOUSE_BUTTON_MIDDLE;
+					mouseEvent.type = ofMouseEventArgs::Released;
+					mb.mouseButtonState &= ~MOUSE_BUTTON_MIDDLE_MASK;
+					pushMouseEvent = true;
+				} else if(ev.value == 1) { // press
+					mb.mouseButtonState |= MOUSE_BUTTON_MIDDLE_MASK;
+					mouseEvent.type = ofMouseEventArgs::Pressed;
+					mouseEvent.button = OF_MOUSE_BUTTON_MIDDLE;
+					pushMouseEvent = true;
+				} else { // unknown
+					ofLogNotice("ofAppEGLWindow") << "readMouseEvents(): EV_KEY : unknown ev.value = " << ev.value;
+				}
+			} else if(ev.code == BTN_RIGHT) {
+				if(ev.value == 0) { // release
+					mouseEvent.button = OF_MOUSE_BUTTON_RIGHT;
+					mouseEvent.type = ofMouseEventArgs::Released;
+					mb.mouseButtonState &= ~MOUSE_BUTTON_RIGHT_MASK;
+					pushMouseEvent = true;
+				} else if(ev.value == 1) { // press
+					mb.mouseButtonState |= MOUSE_BUTTON_RIGHT_MASK;
+					mouseEvent.type = ofMouseEventArgs::Pressed;
+					mouseEvent.button = OF_MOUSE_BUTTON_RIGHT;
+					pushMouseEvent = true;
+				} else {
+					ofLogNotice("ofAppEGLWindow") << "readMouseEvents(): EV_KEY : unknown ev.value = " << ev.value;
+				}
+			} else {
+				ofLogNotice("ofAppEGLWindow") << "readMouseEvents(): EV_KEY : unknown ev.code = " << ev.code;
+			}
+			// not sure why we are getting that event here
+		} else if(ev.type == EV_MSC) {
+			// EV_MSC events are used for input and output events that
+			// do not fall under other categories.
+			// ofLogVerbose("ofAppEGLWindow") << "readMouseEvents() : EV_MSC";
+		} else if(ev.type == EV_SYN ) {
+			// EV_SYN Used as markers to separate events. Events may be
+			// separated in time or in space, such as with the multitouch protocol.
+
+			// EV_SYN events are sent when axis value (one or a pair) are changed
+			if(axisValuePending) {
+				// TODO, this state doesn't make as much sense when the mouse is not dragging
+				if(mb.mouseButtonState > 0) {
+					// dragging (what if dragging w/ more than one button?)
+					mouseEvent.type = ofMouseEventArgs::Dragged;
+				} else {
+					// just moving
+					mouseEvent.type = ofMouseEventArgs::Moved;
+				}
+
+				mouseEvent.button = mb.mouseButtonState;
+
+				pushMouseEvent = true;
+				axisValuePending = false;
+			}
+
+			//ofLogVerbose("ofAppEGLWindow") << "readMouseEvents(): EV_SYN";
+		} else {
+			// unhandled type
+		}
+
+		// do we have a mouse event to push?
+		if(pushMouseEvent){
+			// lock the thread for a moment while we copy the data
+			lock();
+			mouseEvents.push(mouseEvent);
+			unlock();
+			pushMouseEvent = false;
+		}
+
+		// Why another read?
+		nBytesRead = read(mice[i].fildes, &ev,sizeof(struct input_event));
+	} // While loop
+// ------------
+	} // For loop
+
+}
+
+#ifdef TARGET_RASPBERRY_PI
+//------------------------------------------------------------
+void ofAppEGLWindow::initRPiNative() {
+	bcm_host_init();
+
+	memset(&dispman_native_window, 0x0, sizeof(EGL_DISPMANX_WINDOW_T));
+	dispman_element = DISPMANX_NO_HANDLE;
+	dispman_display = DISPMANX_NO_HANDLE;
+	dispman_update  = DISPMANX_NO_HANDLE;
+	memset(&dispman_clamp, 0x0, sizeof(DISPMANX_CLAMP_T));
+	dispman_transform = DISPMANX_NO_ROTATE;
+	memset(&dispman_alpha, 0x0, sizeof(VC_DISPMANX_ALPHA_T)); // zero dispman_alpha
+
+}
+
+//------------------------------------------------------------
+void ofAppEGLWindow::exitRPiNative() {
+	bcm_host_deinit();
+}
+
+//------------------------------------------------------------
+bool ofAppEGLWindow::createRPiNativeWindow(const ofRectangle& requestedWindowRect){
+
+	ofRectangle screenRect = getScreenRect();
+
+	// make sure our requested window rectangle does not exceed the native
+	// screen size, or start outside of it.
+	ofRectangle windowRect = screenRect.getIntersection(requestedWindowRect);
+
+	ofLogNotice("ofAppEGLWindow") << "setupRPiNativeWindow(): screenRect: " << screenRect.width << "x" << screenRect.height;
+	ofLogNotice("ofAppEGLWindow") << "setupRPiNativeWindow(): windowRect: " << windowRect.width << "x" << windowRect.height;
+
+	//////////////////////////
+	VC_RECT_T dst_rect;
+
+	dst_rect.x = (int32_t)windowRect.x;
+	dst_rect.y = (int32_t)windowRect.y;
+	dst_rect.width = (int32_t)windowRect.width;
+	dst_rect.height = (int32_t)windowRect.height;
+
+	VC_RECT_T src_rect;
+
+	src_rect.x = 0;
+	src_rect.y = 0;
+	src_rect.width  = dst_rect.width << 16;
+	src_rect.height = dst_rect.height << 16;
+
+	memset(&dispman_alpha, 0x0, sizeof(VC_DISPMANX_ALPHA_T)); // zero dispman_alpha
+	dispman_alpha.flags = DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS;
+	dispman_alpha.opacity = ofClamp(settings.eglWindowOpacity,0,255);
+	dispman_alpha.mask = 0;
+
+	memset(&dispman_clamp, 0x0, sizeof(DISPMANX_CLAMP_T));
+
+	// there are other values for dispman_transform, but they do not seem to have an effect
+	dispman_transform = DISPMANX_NO_ROTATE;
+
+	// get the zero display
+	dispman_display = vc_dispmanx_display_open(settings.screenNum);
+
+	// begin the display manager interaction
+	dispman_update  = vc_dispmanx_update_start( 0 );
+
+	// add a "display manager element" with our parameters so
+	// that it can fill in the structures.  we will pass this
+	// filled dispman_element to our native window, which will
+	// be used to construct the EGL surface, etc.
+	dispman_element = vc_dispmanx_element_add ( dispman_update,
+			dispman_display,
+			settings.layer, // layer
+			&dst_rect, // dst rect
+			(DISPMANX_RESOURCE_HANDLE_T)0, // src
+			&src_rect, // src rect
+			DISPMANX_PROTECTION_NONE, // ?
+			&dispman_alpha, // alpha
+			&dispman_clamp, // clamp
+			dispman_transform // transform
+	);
+
+	if(dispman_element == DISPMANX_NO_HANDLE) {
+		ofLogError("ofAppEGLWindow") << "setupRPiNativeWindow(): dispman_element == DISPMANX_NO_HANDLE";
+		return false;
+	} else if(dispman_element == (unsigned)DISPMANX_INVALID) {
+		ofLogError("ofAppEGLWindow") << "setupRPiNativeWindow(): dispman_element == DISPMANX_INVALID";
+		return false;
+	}
+
+	// set dispman_native_window to zero
+	memset(&dispman_native_window, 0x0, sizeof(EGL_DISPMANX_WINDOW_T));
+	dispman_native_window.element = dispman_element;
+	dispman_native_window.width = (int32_t)windowRect.width;
+	dispman_native_window.height = (int32_t)windowRect.height;
+
+	// set background to black (not required)
+	vc_dispmanx_display_set_background(dispman_update, dispman_display, 0x00, 0x00, 0x00);
+
+	// finished with display manager update, so sync
+	vc_dispmanx_update_submit_sync( dispman_update );
+
+	currentWindowRect = windowRect;
+
+	return true;
+}
+#endif
+
+//------------------------------------------------------------
+// X11 BELOW
+//------------------------------------------------------------
+bool ofAppEGLWindow::createX11NativeWindow(const ofRectangle& requestedWindowRect){
+
+	// X11 variables
+	x11Window = 0;
+	x11Display = 0;
+	x11ScreenNum = 0; // TODO: settings.screenNum?
+	x11Screen = 0;
+	XVisualInfo* x11Visual = 0; // TODO does this need to be deleted?
+	Colormap x11Colormap = 0;
+
+	/*
+	Step 0 - Create a NativeWindowType that we can use it for OpenGL ES output
+	 */
+	Window sRootWindow;
+	XSetWindowAttributes sWA;
+	unsigned int ui32Mask;
+	int i32Depth;
+
+	//ofRectangle screenRect = getScreenRect();
+
+	// make sure our requested window rectangle does not exceed the native
+	// screen size, or start outside of it.
+	ofRectangle windowRect = requestedWindowRect.getStandardized();//screenRect.getIntersection(requestedWindowRect);
+
+	// Initializes the display and screen
+	x11Display = XOpenDisplay( 0 );
+	if (!x11Display) {
+		ofLogError("ofAppEGLWindow") << "unable to open X display";
+		return false;
+	}
+
+	x11ScreenNum = XDefaultScreen( x11Display );
+
+	x11Screen = XDefaultScreenOfDisplay(x11Display);
+
+	// Gets the window parameters
+	sRootWindow = RootWindow(x11Display, x11ScreenNum);
+	i32Depth = DefaultDepth(x11Display, x11ScreenNum);
+	x11Visual = new XVisualInfo();
+
+	XMatchVisualInfo( x11Display,
+			x11ScreenNum,
+			i32Depth,
+			TrueColor,
+			x11Visual);
+
+	if (!x11Visual) {
+		ofLogError("ofAppEGLWindow") << "unable to acquire XVisualInfo";
+		return false;
+	}
+
+	x11Colormap = XCreateColormap( x11Display, sRootWindow, x11Visual->visual, AllocNone );
+
+	delete x11Visual;
+
+	// set the colormap window attribuet
+	sWA.colormap = x11Colormap;
+
+	// Add to these for handling other events
+	sWA.event_mask = 0;
+	sWA.event_mask |= StructureNotifyMask;
+	sWA.event_mask |= ExposureMask;
+	sWA.event_mask |= ButtonPressMask;
+	sWA.event_mask |= ButtonReleaseMask;
+	sWA.event_mask |= PointerMotionMask;
+	sWA.event_mask |= KeyPressMask;
+	sWA.event_mask |= KeyReleaseMask;
+
+	// setup background pixel attributes
+	ui32Mask = 0;
+	ui32Mask |= CWBackPixel;
+	ui32Mask |= CWBorderPixel;
+	ui32Mask |= CWEventMask;
+	ui32Mask |= CWColormap;
+
+	// Creates the X11 window
+	x11Window = XCreateWindow(x11Display, // Specifies the connection to the X server.
+			sRootWindow, // Specifies the parent window.
+			(int)windowRect.x, (int)windowRect.y, // Specify the x and y coordinates,
+			// which are the top-left outside corner
+			// of the window's borders and are relative
+			// to the inside of the parent window's borders.
+			(unsigned int)windowRect.width, (unsigned int)windowRect.height, // Specify the width and height, which are the
+			// created window's inside dimensions and do
+			// not include the created window's borders.
+			0, // Specifies the width of the created
+			// window's border in pixels.
+			CopyFromParent, // Specifies the window's depth.
+			// A depth of CopyFromParent means
+			// the depth is taken from the parent.
+			InputOutput, // Specifies the created window's class.
+			// You can pass InputOutput, InputOnly,
+			// or CopyFromParent. A class of CopyFromParent
+			// means the class is taken from the parent.
+			CopyFromParent, // Specifies the visual type.
+			// A visual of CopyFromParent means the visual type
+			// is taken from the parent.
+			ui32Mask, // Specifies which window attributes are
+			// defined in the attributes argument. This mask is
+			// the bitwise inclusive OR of the valid attribute
+			// mask bits. If valuemask is zero, the attributes
+			// are ignored and are not referenced.
+			&sWA //Specifies the background pixel value of the window.
+	);
+
+	XMapWindow(x11Display, x11Window);
+	XFlush(x11Display);
+
+	// check success?
+	currentWindowRect = windowRect;
+
+	return true;
+}
+
+//------------------------------------------------------------
+static KeySym KeyCodeToKeySym(Display * display, KeyCode keycode, unsigned int event_mask) {
+	KeySym keysym = NoSymbol;
+
+	//Get the map
+	XkbDescPtr keyboard_map = XkbGetMap(display, XkbAllClientInfoMask, XkbUseCoreKbd);
+	if (keyboard_map) {
+		//What is diff between XkbKeyGroupInfo and XkbKeyNumGroups?
+		unsigned char info = XkbKeyGroupInfo(keyboard_map, keycode);
+		unsigned int num_groups = XkbKeyNumGroups(keyboard_map, keycode);
+
+		//Get the group
+		unsigned int group = 0x00;
+		switch (XkbOutOfRangeGroupAction(info)) {
+		case XkbRedirectIntoRange:
+			/* If the RedirectIntoRange flag is set, the four least significant
+			 * bits of the groups wrap control specify the index of a group to
+			 * which all illegal groups correspond. If the specified group is
+			 * also out of range, all illegal groups map to Group1.
+			 */
+			group = XkbOutOfRangeGroupInfo(info);
+			if (group >= num_groups) {
+				group = 0;
+			}
+			break;
+
+		case XkbClampIntoRange:
+			/* If the ClampIntoRange flag is set, out-of-range groups correspond
+			 * to the nearest legal group. Effective groups larger than the
+			 * highest supported group are mapped to the highest supported group;
+			 * effective groups less than Group1 are mapped to Group1 . For
+			 * example, a key with two groups of symbols uses Group2 type and
+			 * symbols if the global effective group is either Group3 or Group4.
+			 */
+			group = num_groups - 1;
+			break;
+
+		case XkbWrapIntoRange:
+			/* If neither flag is set, group is wrapped into range using integer
+			 * modulus. For example, a key with two groups of symbols for which
+			 * groups wrap uses Group1 symbols if the global effective group is
+			 * Group3 or Group2 symbols if the global effective group is Group4.
+			 */
+		default:
+			if (num_groups != 0) {
+				group %= num_groups;
+			}
+			break;
+		}
+
+		XkbKeyTypePtr key_type = XkbKeyKeyType(keyboard_map, keycode, group);
+		unsigned int active_mods = event_mask & key_type->mods.mask;
+
+		int i, level = 0;
+		for (i = 0; i < key_type->map_count; i++) {
+			if (key_type->map[i].active && key_type->map[i].mods.mask == active_mods) {
+				level = key_type->map[i].level;
+			}
+		}
+
+		keysym = XkbKeySymEntry(keyboard_map, keycode, level, group);
+		XkbFreeClientMap(keyboard_map, XkbAllClientInfoMask, true);
+	}
+
+	return keysym;
+}
+
+//------------------------------------------------------------
+void ofAppEGLWindow::handleX11Event(const XEvent& event){
+	ofMouseEventArgs mouseEvent;
+	ofKeyEventArgs keyEvent;
+	switch (event.type){
+	case KeyPress:
+	case KeyRelease:
+	{
+		KeySym key = KeyCodeToKeySym(instance->x11Display,event.xkey.keycode,event.xkey.state);
+		keyEvent.key = key;
+		if (event.type == KeyPress) {
+			keyEvent.type = ofKeyEventArgs::Pressed;
+			if(key == 65307){
+				keyEvent.key = OF_KEY_ESC;
+			}
+		} else if (event.type == KeyRelease){
+			keyEvent.type = ofKeyEventArgs::Released;
+		}
+
+		instance->coreEvents.notifyKeyEvent(keyEvent);
+	}
+	break;
+	case ButtonPress:
+	case ButtonRelease:
+		mouseEvent.x = static_cast<float>(event.xbutton.x);
+		mouseEvent.y = static_cast<float>(event.xbutton.y);
+		mouseEvent.button = event.xbutton.button;
+		if (event.type == ButtonPress){
+			mouseEvent.type = ofMouseEventArgs::Pressed;
+		} else {
+			mouseEvent.type = ofMouseEventArgs::Released;
+		}
+
+		instance->coreEvents.notifyMouseEvent(mouseEvent);
+		break;
+	case MotionNotify:
+		//cout << "motion notify" << endl;
+		mouseEvent.x = static_cast<float>(event.xmotion.x);
+		mouseEvent.y = static_cast<float>(event.xmotion.y);
+		mouseEvent.button = event.xbutton.button;
+		if(ofGetMousePressed()) {
+			mouseEvent.type = ofMouseEventArgs::Dragged;
+		} else {
+			mouseEvent.type = ofMouseEventArgs::Moved;
+		}
+
+		instance->coreEvents.notifyMouseEvent(mouseEvent);
+		break;
+	case ConfigureNotify:
+		instance->currentWindowRect.x = event.xconfigure.x;
+		instance->currentWindowRect.y = event.xconfigure.y;
+		instance->currentWindowRect.width = event.xconfigure.width;
+		instance->currentWindowRect.height = event.xconfigure.height;
+		instance->nonFullscreenWindowRect = instance->currentWindowRect;
+		instance->coreEvents.notifyWindowResized(event.xconfigure.width,event.xconfigure.height);
+		break;
+	/*case ClientMessage:{
+		if (event.xclient.message_type == wmProtocols_ &&
+		event.xclient.format == 32 &&
+		event.xclient.data.l[0] == (long) wmDeleteWindow_)
+		{
+		if (listener())
+		{
+		  if (listener()->onClose(wrapper() ? *wrapper() : *(WindowInterface*)this))
+			isShuttingDown_ = true;
+		}
+		else
+		{
+		  isShuttingDown_ = true;
+		}
+		}
+		break;
+	  }*/
+	}
+}
diff --git a/ofpatch/ofAppEGLWindow.h b/ofpatch/ofAppEGLWindow.h
new file mode 100644
index 0000000..8a55a88
--- /dev/null
+++ b/ofpatch/ofAppEGLWindow.h
@@ -0,0 +1,310 @@
+#pragma once
+
+#include "ofBaseApp.h"
+
+#include "ofAppBaseWindow.h"
+#include "ofThread.h"
+#include "ofImage.h"
+#include "ofBaseTypes.h"
+#include "ofEvents.h"
+#include "ofConstants.h"
+#include "ofTypes.h"
+
+// include includes for both native and X11 possibilities
+#include <libudev.h>
+#include <stdbool.h>
+#include <stdio.h> // sprintf
+#include <stdlib.h>  // malloc
+#include <math.h>
+#include <fcntl.h>  // open fcntl
+#include <unistd.h> // read close 
+#include <linux/joystick.h>
+
+#include "linux/kd.h"	// keyboard stuff...
+#include "termios.h"
+#include "sys/ioctl.h"
+
+#include <dirent.h>  // scandir
+#include <string.h> // strlen
+
+// x11
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+#include <queue>
+#include <map>
+
+#include <EGL/egl.h>
+
+// TODO: this shold be passed in with the other window settings, like window alpha, etc.
+enum ofAppEGLWindowType {
+	OF_APP_WINDOW_AUTO,
+	OF_APP_WINDOW_NATIVE,
+	OF_APP_WINDOW_X11
+};
+
+struct ofAppEGLWindowMouseArgs {
+	string deviceName;
+	int fildes; // File Descriptor
+	int absXMin;
+	int absXMax;
+	int absYMin;
+	int absYMax;
+	float scaleX;
+	float scaleY;
+};
+
+typedef std::map<EGLint,EGLint> ofEGLAttributeList;
+typedef std::map<EGLint,EGLint>::iterator ofEGLAttributeListIterator;
+
+class ofAppEGLWindow : public ofAppBaseGLESWindow, public ofThread {
+public:
+
+	struct Settings;
+
+	ofAppEGLWindow();
+	virtual ~ofAppEGLWindow();
+
+	static void loop(){};
+	static bool doesLoop(){ return false; }
+	static bool allowsMultiWindow(){ return false; }
+	static bool needsPolling(){ return true; }
+	static void pollEvents();
+
+	using ofAppBaseGLESWindow::setup;
+	void setup(const Settings & settings);
+	void setup(const ofGLESWindowSettings & settings);
+
+	void update();
+	void draw();
+	void close();
+	void makeCurrent();
+	void swapBuffers();
+	void startRender();
+	void finishRender();
+
+	ofCoreEvents & events();
+	std::shared_ptr<ofBaseRenderer> & renderer();
+
+	void setThreadTimeout(long timeOut){ threadTimeout = timeOut; }
+
+	virtual void hideCursor();
+	virtual void showCursor();
+
+	virtual void setWindowPosition(int x, int y);
+	virtual void setWindowShape(int w, int h);
+
+	virtual glm::vec2 getWindowPosition();
+	virtual glm::vec2 getWindowSize();
+	virtual glm::vec2 getScreenSize();
+
+	virtual void setOrientation(ofOrientation orientation);
+	virtual ofOrientation getOrientation();
+	virtual bool doesHWOrientation();
+
+	//this is used by ofGetWidth and now determines the window width based on orientation
+	virtual int	getWidth();
+	virtual int	getHeight();
+
+	virtual void setWindowTitle(std::string title); // TODO const correct
+
+	virtual ofWindowMode getWindowMode();
+
+	virtual void setFullscreen(bool fullscreen);
+	virtual void toggleFullscreen();
+
+	virtual void enableSetupScreen();
+	virtual void disableSetupScreen();
+
+	virtual void setVerticalSync(bool enabled);
+	
+	struct Settings: public ofGLESWindowSettings {
+		public:
+		ofAppEGLWindowType eglWindowPreference;  // what window type is preferred?
+		EGLint eglWindowOpacity; // 0-255 window alpha value
+
+		ofEGLAttributeList frameBufferAttributes;
+		// surface creation
+		ofEGLAttributeList windowSurfaceAttributes;
+
+		ofColor initialClearColor;
+
+		int screenNum;
+		int layer;
+
+		Settings();
+		Settings(const ofGLESWindowSettings & settings);
+	};
+
+	EGLDisplay getEglDisplay() const;
+	EGLSurface getEglSurface() const;
+	EGLContext getEglContext() const;
+
+#ifndef TARGET_RASPBERRY_PI
+	Display* getX11Display();
+	Window getX11Window();
+#endif
+
+	EGLConfig getEglConfig() const;
+
+	EGLint getEglVersionMajor () const;
+	EGLint getEglVersionMinor() const;
+
+
+protected:
+	void setWindowRect(const ofRectangle& requestedWindowRect);
+
+
+//	bool create
+
+	virtual void setupPeripherals();
+
+	virtual ofRectangle getScreenRect();
+
+	int getWindowWidth();
+	int getWindowHeight();
+
+	ofWindowMode windowMode;
+	bool bNewScreenMode;  ///< \brief This indicates if a (new) window rectangle has to be adjusted.
+	int	buttonInUse;  ///< \brief Mouse button currently in use.
+	bool bEnableSetupScreen;  ///< \brief This indicates the need/intent to draw a setup screen.
+	bool bShowCursor;  ///< \brief Indicate the visibility of the (mouse) cursor.
+
+	std::string eglDisplayString;
+	int nFramesSinceWindowResized;  ///< \brief The number of frames passed/shown since the window got resized.
+	ofOrientation orientation;
+
+
+	void threadedFunction();
+	std::queue<ofMouseEventArgs> mouseEvents;
+	std::queue<ofKeyEventArgs>   keyEvents;
+	void checkEvents();
+	ofImage mouseCursor;
+
+	// TODO: getters and setters?  OR automatically set based on 
+	// OS or screen size?  Should be changed when screen is resized?
+	float mouseScaleX;  ///< \brief Amount by which to mouse movements along the X axis.
+	float mouseScaleY;  ///< \brief Amount by which to mouse movements along the Y axis.
+
+
+	// float getMouseScaleX() const;
+	// void setMouseScaleX(float x);
+	// float getMouseScaleY() const;
+	// void setMouseScaleY(float y);
+
+	// For absolute input devices that send ABS_X and ABS_Y events, we want to store
+	// information about the min and max axis values.
+	int mouseAbsXMin;
+	int mouseAbsXMax;
+	int mouseAbsYMin;
+	int mouseAbsYMax;
+
+	// TODO: a list of all valid and open mouse devices
+	// Store open mouse device file descriptors
+	vector<ofAppEGLWindowMouseArgs> mice;
+	
+	bool hasMouse() { return mouseDetected; }
+	bool hasKeyboard() { return keyboardDetected; }
+	
+
+//------------------------------------------------------------
+// EGL
+//------------------------------------------------------------
+
+	bool createSurface();
+	bool destroySurface();
+
+	// bool resizeSurface();
+
+	EGLDisplay eglDisplay;  // EGL display connection
+	EGLSurface eglSurface;
+	EGLContext eglContext;
+
+	EGLConfig eglConfig;
+
+	EGLint eglVersionMajor;
+	EGLint eglVersionMinor;
+
+//------------------------------------------------------------
+// PLATFORM SPECIFIC WINDOWING
+//------------------------------------------------------------
+	
+//------------------------------------------------------------
+// WINDOWING
+//------------------------------------------------------------
+	// EGL window
+	ofRectangle nonFullscreenWindowRect; // the rectangle describing the non-fullscreen window
+	ofRectangle currentWindowRect; // the rectangle describing the current device
+
+	bool createWindow(const ofRectangle& requestedWindowRect);
+	bool destroyWindow();
+
+	bool isUsingX11;  ///< \brief Indicate the use of the X Window System.
+
+	bool isWindowInited;  ///< \brief Indicate that the window is (properly) initialized.
+	bool isSurfaceInited;  ///< \brief Indicate that the surface is (properly) initialized.
+
+	void initNative();
+	void exitNative();
+
+	EGLNativeWindowType getNativeWindow();
+	EGLNativeDisplayType getNativeDisplay();
+
+#ifdef TARGET_RASPBERRY_PI
+	void initRPiNative();
+	void exitRPiNative();
+
+	EGL_DISPMANX_WINDOW_T dispman_native_window; // rpi
+
+	DISPMANX_UPDATE_HANDLE_T dispman_update;
+	DISPMANX_ELEMENT_HANDLE_T dispman_element;
+	DISPMANX_DISPLAY_HANDLE_T dispman_display;
+
+	DISPMANX_CLAMP_T  dispman_clamp;
+	DISPMANX_TRANSFORM_T dispman_transform;
+	VC_DISPMANX_ALPHA_T	dispman_alpha;
+	
+	bool createRPiNativeWindow(const ofRectangle& requestedWindowRect);
+
+#else
+	// if you are not raspberry pi, you will not be able to
+	// create a window without using x11.
+#endif
+
+	Display* x11Display;  ///< \brief Indicate which X11 display is in use (currently).
+	Screen* x11Screen;  ///< \brief Indicate which X11 screen is in use (currently).
+	Window x11Window;
+	long x11ScreenNum;  ///< \brief The number of the X11 screen is in use (currently).
+	bool createX11NativeWindow(const ofRectangle& requestedWindowRect);
+	 
+//------------------------------------------------------------
+// EVENTS
+//------------------------------------------------------------
+	void setupNativeEvents();
+	void destroyNativeEvents();
+
+	void setupNativeUDev();
+	void destroyNativeUDev();
+	
+	void setupNativeMouse();
+	void setupNativeKeyboard();
+
+	void destroyNativeMouse();
+	void destroyNativeKeyboard();
+
+	void readNativeMouseEvents();
+	void readNativeKeyboardEvents();
+	void readNativeUDevEvents();
+
+	static void handleX11Event(const XEvent& event);
+
+private:
+	Settings settings;
+	int glesVersion;  ///< \brief Indicate the version of OpenGL for Embedded Systems.
+	bool keyboardDetected;
+	bool mouseDetected;
+	long threadTimeout;
+	ofCoreEvents coreEvents;
+	std::shared_ptr<ofBaseRenderer> currentRenderer;
+	static ofAppEGLWindow * instance;
+};