Wayland support
authorGabriel Jacobo <gabomdq@gmail.com>
Sat, 14 Dec 2013 20:18:43 -0300
changeset 8062 4fc5f66d63cc
parent 8061 a5f8137ccf01
child 8063 405d84eedad8
Wayland support Based on the original port to Wayland by: Joel Teichroeb, Benjamin Franzke, Scott Moreau, et al. Additional changes in this commit, done by me: * Wayland uses the common EGL framework * EGL can now create a desktop OpenGL context * testgl2 loads GL functions dynamically, no need to link to libGL anymore * Assorted fixes to the Wayland backend Tested on the Weston Compositor (v1.0.5) that ships with Ubuntu 13.10, running Weston under X. Tests ran: testrendercopyex (all backends), testgl2, testgles2,testintersections
CMakeLists.txt
WhatsNew.txt
cmake/sdlchecks.cmake
configure
configure.in
include/SDL_config.h.cmake
include/SDL_config.h.in
include/SDL_syswm.h
src/render/opengl/SDL_glfuncs.h
src/video/SDL_egl.c
src/video/SDL_egl_c.h
src/video/SDL_sysvideo.h
src/video/SDL_video.c
src/video/wayland/SDL_waylandevents.c
src/video/wayland/SDL_waylandevents_c.h
src/video/wayland/SDL_waylandmouse.c
src/video/wayland/SDL_waylandmouse.h
src/video/wayland/SDL_waylandopengles.c
src/video/wayland/SDL_waylandopengles.h
src/video/wayland/SDL_waylandvideo.c
src/video/wayland/SDL_waylandvideo.h
src/video/wayland/SDL_waylandwindow.c
src/video/wayland/SDL_waylandwindow.h
test/Makefile.in
test/testgl2.c
--- a/CMakeLists.txt	Fri Dec 13 09:48:12 2013 -0300
+++ b/CMakeLists.txt	Sat Dec 14 20:18:43 2013 -0300
@@ -218,6 +218,7 @@
 set_option(CLOCK_GETTIME       "Use clock_gettime() instead of gettimeofday()" OFF)
 set_option(INPUT_TSLIB         "Use the Touchscreen library for input" ${UNIX_SYS})
 set_option(VIDEO_X11           "Use X11 video driver" ${UNIX_SYS})
+set_option(VIDEO_WAYLAND       "Use Wayland video driver" ${UNIX_SYS})
 dep_option(X11_SHARED          "Dynamically load X11 support" ON "VIDEO_X11" OFF)
 set(SDL_X11_OPTIONS Xcursor Xinerama XInput Xrandr Xscrnsaver XShape Xvm)
 foreach(_SUB ${SDL_X11_OPTIONS})
@@ -641,6 +642,7 @@
     CheckDirectFB()
     CheckOpenGLX11()
     CheckOpenGLESX11()
+    CheckWayland()
   endif(SDL_VIDEO)
 
   if(LINUX)
--- a/WhatsNew.txt	Fri Dec 13 09:48:12 2013 -0300
+++ b/WhatsNew.txt	Sat Dec 14 20:18:43 2013 -0300
@@ -7,7 +7,10 @@
 General:
 * Added an API to load a database of Game Controller mappings from a file:    
     SDL_GameControllerAddMappingsFromFile
-    
+* EGL can now create/manage OpenGL and OpenGL ES 1.x/2.x contexts, and share
+  them using SDL_GL_SHARE_WITH_CURRENT_CONTEXT
+* Added testgles2. testgl2 does not need to link with libGL anymore.
+  
 Windows:
 * Support for OpenGL ES 2.x contexts using either WGL or EGL (natively via
   the driver or emulated through ANGLE)
@@ -20,7 +23,7 @@
 
 Linux:
 * Fixed fullscreen and focused behavior when receiving NotifyGrab events
-
+* Wayland support
 
 ---------------------------------------------------------------------------
 2.0.1:
--- a/cmake/sdlchecks.cmake	Fri Dec 13 09:48:12 2013 -0300
+++ b/cmake/sdlchecks.cmake	Sat Dec 14 20:18:43 2013 -0300
@@ -506,6 +506,29 @@
 endmacro(CheckX11)
 
 # Requires:
+# - EGL
+macro(CheckWayland)
+  if(VIDEO_WAYLAND)
+    pkg_check_modules(WAYLAND wayland-client wayland-cursor wayland-egl egl xkbcommon)
+    if(WAYLAND_FOUND)
+      link_directories(
+          ${WAYLAND_LIBRARY_DIRS}
+      )
+      include_directories(
+          ${WAYLAND_INCLUDE_DIRS}
+      )
+      set(EXTRA_LIBS ${WAYLAND_LIBRARIES} ${EXTRA_LIBS})
+      set(HAVE_VIDEO_WAYLAND TRUE)
+      set(HAVE_SDL_VIDEO TRUE)
+
+      file(GLOB WAYLAND_SOURCES ${SDL2_SOURCE_DIR}/src/video/wayland/*.c)
+      set(SOURCE_FILES ${SOURCE_FILES} ${WAYLAND_SOURCES})
+      set(SDL_VIDEO_DRIVER_WAYLAND 1)
+    endif(WAYLAND_FOUND)
+  endif(VIDEO_WAYLAND)
+endmacro(CheckWayland)
+
+# Requires:
 # - n/a
 #
 macro(CheckCOCOA)
--- a/configure	Fri Dec 13 09:48:12 2013 -0300
+++ b/configure	Sat Dec 14 20:18:43 2013 -0300
@@ -817,6 +817,7 @@
 enable_sndio_shared
 enable_diskaudio
 enable_dummyaudio
+enable_video_wayland
 enable_video_x11
 with_x
 enable_x11_shared
@@ -1532,6 +1533,7 @@
   --enable-sndio-shared   dynamically load sndio audio support [[default=yes]]
   --enable-diskaudio      support the disk writer audio driver [[default=yes]]
   --enable-dummyaudio     support the dummy audio driver [[default=yes]]
+  --enable-video-wayland  use Wayland video driver [[default=yes]]
   --enable-video-x11      use X11 video driver [[default=yes]]
   --enable-x11-shared     dynamically load X11 support [[default=maybe]]
   --enable-video-x11-xcursor
@@ -18633,6 +18635,82 @@
     fi
 }
 
+CheckWayland()
+{
+    # Check whether --enable-video-wayland was given.
+if test "${enable_video_wayland+set}" = set; then :
+  enableval=$enable_video_wayland;
+else
+  enable_video_wayland=yes
+fi
+
+
+    if test x$enable_video = xyes -a x$enable_video_wayland = xyes; then
+        # Extract the first word of "pkg-config", so it can be a program name with args.
+set dummy pkg-config; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_PKG_CONFIG+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $PKG_CONFIG in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  test -z "$ac_cv_path_PKG_CONFIG" && ac_cv_path_PKG_CONFIG="no"
+  ;;
+esac
+fi
+PKG_CONFIG=$ac_cv_path_PKG_CONFIG
+if test -n "$PKG_CONFIG"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5
+$as_echo "$PKG_CONFIG" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+        { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Wayland support" >&5
+$as_echo_n "checking for Wayland support... " >&6; }
+        video_wayland=no
+        if test x$PKG_CONFIG != xno; then
+            if $PKG_CONFIG --exists wayland-client wayland-egl wayland-cursor egl xkbcommon ; then
+                WAYLAND_CFLAGS=`$PKG_CONFIG --cflags wayland-client wayland-egl wayland-cursor egl xkbcommon`
+                WAYLAND_LIBS=`$PKG_CONFIG --libs wayland-client wayland-egl wayland-cursor egl xkbcommon`
+                video_wayland=yes
+            fi
+        fi
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: $video_wayland" >&5
+$as_echo "$video_wayland" >&6; }
+
+        if test x$video_wayland = xyes; then
+
+$as_echo "#define SDL_VIDEO_DRIVER_WAYLAND 1" >>confdefs.h
+
+            SOURCES="$SOURCES $srcdir/src/video/wayland/*.c"
+            EXTRA_CFLAGS="$EXTRA_CFLAGS $WAYLAND_CFLAGS"
+                        EXTRA_LDFLAGS="$EXTRA_LDFLAGS $WAYLAND_LIBS"
+            have_video=yes
+        fi
+    fi
+}
 
 CheckX11()
 {
@@ -22220,6 +22298,7 @@
         CheckNAS
         CheckSNDIO
         CheckX11
+        CheckWayland
         CheckDirectFB
         CheckFusionSound
         CheckOpenGLX11
--- a/configure.in	Fri Dec 13 09:48:12 2013 -0300
+++ b/configure.in	Sat Dec 14 20:18:43 2013 -0300
@@ -1115,6 +1115,36 @@
     fi
 }
 
+dnl Check for Wayland
+CheckWayland()
+{
+    AC_ARG_ENABLE(video-wayland,
+AC_HELP_STRING([--enable-video-wayland], [use Wayland video driver [[default=yes]]]),
+                  ,enable_video_wayland=yes)
+
+    if test x$enable_video = xyes -a x$enable_video_wayland = xyes; then
+        AC_PATH_PROG(PKG_CONFIG, pkg-config, no)
+        AC_MSG_CHECKING(for Wayland support)
+        video_wayland=no
+        if test x$PKG_CONFIG != xno; then
+            if $PKG_CONFIG --exists wayland-client wayland-egl wayland-cursor egl xkbcommon ; then
+                WAYLAND_CFLAGS=`$PKG_CONFIG --cflags wayland-client wayland-egl wayland-cursor egl xkbcommon`
+                WAYLAND_LIBS=`$PKG_CONFIG --libs wayland-client wayland-egl wayland-cursor egl xkbcommon`
+                video_wayland=yes
+            fi
+        fi
+        AC_MSG_RESULT($video_wayland)
+
+        if test x$video_wayland = xyes; then
+            AC_DEFINE(SDL_VIDEO_DRIVER_WAYLAND, 1, [ ])
+            SOURCES="$SOURCES $srcdir/src/video/wayland/*.c"
+            EXTRA_CFLAGS="$EXTRA_CFLAGS $WAYLAND_CFLAGS"
+            dnl FIXME do dynamic loading code here.
+            EXTRA_LDFLAGS="$EXTRA_LDFLAGS $WAYLAND_LIBS"
+            have_video=yes
+        fi
+    fi
+}
 
 dnl Find the X11 include and library directories
 CheckX11()
@@ -2449,6 +2479,7 @@
         CheckNAS
         CheckSNDIO
         CheckX11
+        CheckWayland
         CheckDirectFB
         CheckFusionSound
         CheckOpenGLX11
--- a/include/SDL_config.h.cmake	Fri Dec 13 09:48:12 2013 -0300
+++ b/include/SDL_config.h.cmake	Sat Dec 14 20:18:43 2013 -0300
@@ -259,6 +259,7 @@
 #cmakedefine SDL_VIDEO_DRIVER_DIRECTFB_DYNAMIC @SDL_VIDEO_DRIVER_DIRECTFB_DYNAMIC@
 #cmakedefine SDL_VIDEO_DRIVER_DUMMY @SDL_VIDEO_DRIVER_DUMMY@
 #cmakedefine SDL_VIDEO_DRIVER_WINDOWS @SDL_VIDEO_DRIVER_WINDOWS@
+#cmakedefine SDL_VIDEO_DRIVER_WAYLAND @SDL_VIDEO_DRIVER_WAYLAND@
 #cmakedefine SDL_VIDEO_DRIVER_X11 @SDL_VIDEO_DRIVER_X11@
 #cmakedefine SDL_VIDEO_DRIVER_X11_DYNAMIC @SDL_VIDEO_DRIVER_X11_DYNAMIC@
 #cmakedefine SDL_VIDEO_DRIVER_X11_DYNAMIC_XEXT @SDL_VIDEO_DRIVER_X11_DYNAMIC_XEXT@
--- a/include/SDL_config.h.in	Fri Dec 13 09:48:12 2013 -0300
+++ b/include/SDL_config.h.in	Sat Dec 14 20:18:43 2013 -0300
@@ -260,6 +260,7 @@
 #undef SDL_VIDEO_DRIVER_DIRECTFB_DYNAMIC
 #undef SDL_VIDEO_DRIVER_DUMMY
 #undef SDL_VIDEO_DRIVER_WINDOWS
+#undef SDL_VIDEO_DRIVER_WAYLAND
 #undef SDL_VIDEO_DRIVER_X11
 #undef SDL_VIDEO_DRIVER_RPI
 #undef SDL_VIDEO_DRIVER_X11_DYNAMIC
--- a/include/SDL_syswm.h	Fri Dec 13 09:48:12 2013 -0300
+++ b/include/SDL_syswm.h	Sat Dec 14 20:18:43 2013 -0300
@@ -101,6 +101,7 @@
     SDL_SYSWM_UNKNOWN,
     SDL_SYSWM_WINDOWS,
     SDL_SYSWM_X11,
+    SDL_SYSWM_WAYLAND,
     SDL_SYSWM_DIRECTFB,
     SDL_SYSWM_COCOA,
     SDL_SYSWM_UIKIT,
@@ -175,6 +176,14 @@
             Window window;              /**< The X11 window */
         } x11;
 #endif
+#if defined(SDL_VIDEO_DRIVER_WAYLAND)
+        struct
+        {
+            struct wl_display *display;            /**< Wayland display */
+            struct wl_surface *surface;            /**< Wayland surface */
+            struct wl_shell_surface *shell_surface; /**< Wayland shell_surface (window manager handle) */
+        } wl;
+#endif
 #if defined(SDL_VIDEO_DRIVER_DIRECTFB)
         struct
         {
--- a/src/render/opengl/SDL_glfuncs.h	Fri Dec 13 09:48:12 2013 -0300
+++ b/src/render/opengl/SDL_glfuncs.h	Sat Dec 14 20:18:43 2013 -0300
@@ -30,7 +30,7 @@
 SDL_PROC_UNUSED(void, glColor3d, (GLdouble, GLdouble, GLdouble))
 SDL_PROC_UNUSED(void, glColor3dv, (const GLdouble *))
 SDL_PROC_UNUSED(void, glColor3f, (GLfloat, GLfloat, GLfloat))
-SDL_PROC_UNUSED(void, glColor3fv, (const GLfloat *))
+SDL_PROC(void, glColor3fv, (const GLfloat *))
 SDL_PROC_UNUSED(void, glColor3i, (GLint, GLint, GLint))
 SDL_PROC_UNUSED(void, glColor3iv, (const GLint *))
 SDL_PROC_UNUSED(void, glColor3s, (GLshort, GLshort, GLshort))
@@ -85,7 +85,7 @@
 SDL_PROC_UNUSED(void, glCullFace, (GLenum mode))
 SDL_PROC_UNUSED(void, glDeleteLists, (GLuint list, GLsizei range))
 SDL_PROC(void, glDeleteTextures, (GLsizei n, const GLuint * textures))
-SDL_PROC_UNUSED(void, glDepthFunc, (GLenum func))
+SDL_PROC(void, glDepthFunc, (GLenum func))
 SDL_PROC_UNUSED(void, glDepthMask, (GLboolean flag))
 SDL_PROC_UNUSED(void, glDepthRange, (GLclampd zNear, GLclampd zFar))
 SDL_PROC(void, glDisable, (GLenum cap))
@@ -334,13 +334,13 @@
 SDL_PROC_UNUSED(GLint, glRenderMode, (GLenum mode))
 SDL_PROC(void, glRotated,
                 (GLdouble angle, GLdouble x, GLdouble y, GLdouble z))
-SDL_PROC_UNUSED(void, glRotatef,
+SDL_PROC(void, glRotatef,
                 (GLfloat angle, GLfloat x, GLfloat y, GLfloat z))
 SDL_PROC_UNUSED(void, glScaled, (GLdouble x, GLdouble y, GLdouble z))
 SDL_PROC_UNUSED(void, glScalef, (GLfloat x, GLfloat y, GLfloat z))
 SDL_PROC(void, glScissor, (GLint x, GLint y, GLsizei width, GLsizei height))
 SDL_PROC_UNUSED(void, glSelectBuffer, (GLsizei size, GLuint * buffer))
-SDL_PROC_UNUSED(void, glShadeModel, (GLenum mode))
+SDL_PROC(void, glShadeModel, (GLenum mode))
 SDL_PROC_UNUSED(void, glStencilFunc, (GLenum func, GLint ref, GLuint mask))
 SDL_PROC_UNUSED(void, glStencilMask, (GLuint mask))
 SDL_PROC_UNUSED(void, glStencilOp, (GLenum fail, GLenum zfail, GLenum zpass))
@@ -432,7 +432,7 @@
 SDL_PROC_UNUSED(void, glVertex3d, (GLdouble x, GLdouble y, GLdouble z))
 SDL_PROC_UNUSED(void, glVertex3dv, (const GLdouble * v))
 SDL_PROC_UNUSED(void, glVertex3f, (GLfloat x, GLfloat y, GLfloat z))
-SDL_PROC_UNUSED(void, glVertex3fv, (const GLfloat * v))
+SDL_PROC(void, glVertex3fv, (const GLfloat * v))
 SDL_PROC_UNUSED(void, glVertex3i, (GLint x, GLint y, GLint z))
 SDL_PROC_UNUSED(void, glVertex3iv, (const GLint * v))
 SDL_PROC_UNUSED(void, glVertex3s, (GLshort x, GLshort y, GLshort z))
--- a/src/video/SDL_egl.c	Fri Dec 13 09:48:12 2013 -0300
+++ b/src/video/SDL_egl.c	Sat Dec 14 20:18:43 2013 -0300
@@ -50,6 +50,7 @@
 
 #else
 /* Desktop Linux */
+#define DEFAULT_OGL "libGL.so.1"
 #define DEFAULT_EGL "libEGL.so.1"
 #define DEFAULT_OGL_ES2 "libGLESv2.so.2"
 #define DEFAULT_OGL_ES_PVR "libGLES_CM.so.1"
@@ -149,23 +150,31 @@
     }
 
     if (egl_dll_handle == NULL) {
-        if (_this->gl_config.major_version > 1) {
-            path = DEFAULT_OGL_ES2;
+        if(_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) {
+            if (_this->gl_config.major_version > 1) {
+                path = DEFAULT_OGL_ES2;
+                egl_dll_handle = SDL_LoadObject(path);
+            }
+            else {
+                path = DEFAULT_OGL_ES;
+                egl_dll_handle = SDL_LoadObject(path);
+                if (egl_dll_handle == NULL) {
+                    path = DEFAULT_OGL_ES_PVR;
+                    egl_dll_handle = SDL_LoadObject(path);
+                }
+            }
+        }
+#ifdef DEFAULT_OGL         
+        else {
+            path = DEFAULT_OGL;
             egl_dll_handle = SDL_LoadObject(path);
         }
-        else {
-            path = DEFAULT_OGL_ES;
-            egl_dll_handle = SDL_LoadObject(path);
-            if (egl_dll_handle == NULL) {
-                path = DEFAULT_OGL_ES_PVR;
-                egl_dll_handle = SDL_LoadObject(path);
-            }
-        }
+#endif        
     }
     _this->egl_data->egl_dll_handle = egl_dll_handle;
 
     if (egl_dll_handle == NULL) {
-        return SDL_SetError("Could not initialize OpenGL ES library");
+        return SDL_SetError("Could not initialize OpenGL / GLES library");
     }
 
     /* Loading libGL* in the previous step took care of loading libEGL.so, but we future proof by double checking */
@@ -205,6 +214,7 @@
     LOAD_FUNC(eglSwapInterval);
     LOAD_FUNC(eglWaitNative);
     LOAD_FUNC(eglWaitGL);
+    LOAD_FUNC(eglBindAPI);
     
     _this->egl_data->egl_display = _this->egl_data->eglGetDisplay(native_display);
     if (!_this->egl_data->egl_display) {
@@ -281,14 +291,21 @@
     }
     
     attribs[i++] = EGL_RENDERABLE_TYPE;
-    if (_this->gl_config.major_version == 2) {
-        attribs[i++] = EGL_OPENGL_ES2_BIT;
-    } else {
-        attribs[i++] = EGL_OPENGL_ES_BIT;
+    if(_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) {
+        if (_this->gl_config.major_version == 2) {
+            attribs[i++] = EGL_OPENGL_ES2_BIT;
+        } else {
+            attribs[i++] = EGL_OPENGL_ES_BIT;
+        }
+        _this->egl_data->eglBindAPI(EGL_OPENGL_ES_API);
+    }
+    else {
+        attribs[i++] = EGL_OPENGL_BIT;
+        _this->egl_data->eglBindAPI(EGL_OPENGL_API);
     }
     
     attribs[i++] = EGL_NONE;
-    
+   
     if (_this->egl_data->eglChooseConfig(_this->egl_data->egl_display,
         attribs,
         configs, SDL_arraysize(configs),
@@ -347,18 +364,27 @@
         return NULL;
     }
     
-    if (_this->gl_config.major_version) {
-        context_attrib_list[1] = _this->gl_config.major_version;
-    }
-    
     if (_this->gl_config.share_with_current_context) {
         share_context = (EGLContext)SDL_GL_GetCurrentContext();
     }
+    
+    /* Bind the API */
+    if(_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) {
+        _this->egl_data->eglBindAPI(EGL_OPENGL_ES_API);
+        if (_this->gl_config.major_version) {
+            context_attrib_list[1] = _this->gl_config.major_version;
+        }
 
-    egl_context =
-    _this->egl_data->eglCreateContext(_this->egl_data->egl_display,
-                                      _this->egl_data->egl_config,
-                                      share_context, context_attrib_list);
+        egl_context = _this->egl_data->eglCreateContext(_this->egl_data->egl_display,
+                                          _this->egl_data->egl_config,
+                                          share_context, context_attrib_list);
+    }
+    else {
+        _this->egl_data->eglBindAPI(EGL_OPENGL_API);
+        egl_context = _this->egl_data->eglCreateContext(_this->egl_data->egl_display,
+                                          _this->egl_data->egl_config,
+                                          share_context, NULL);
+    }
     
     if (egl_context == EGL_NO_CONTEXT) {
         SDL_SetError("Could not create EGL context");
--- a/src/video/SDL_egl_c.h	Fri Dec 13 09:48:12 2013 -0300
+++ b/src/video/SDL_egl_c.h	Sat Dec 14 20:18:43 2013 -0300
@@ -76,6 +76,9 @@
     EGLBoolean(EGLAPIENTRY *eglWaitNative) (EGLint  engine);
 
     EGLBoolean(EGLAPIENTRY *eglWaitGL)(void);
+    
+    EGLBoolean(EGLAPIENTRY *eglBindAPI)(EGLenum);
+
 } SDL_EGL_VideoData;
 
 /* OpenGLES functions */
--- a/src/video/SDL_sysvideo.h	Fri Dec 13 09:48:12 2013 -0300
+++ b/src/video/SDL_sysvideo.h	Sat Dec 14 20:18:43 2013 -0300
@@ -369,6 +369,9 @@
 #if SDL_VIDEO_DRIVER_DUMMY
 extern VideoBootStrap DUMMY_bootstrap;
 #endif
+#if SDL_VIDEO_DRIVER_WAYLAND
+extern VideoBootStrap Wayland_bootstrap;
+#endif
 
 extern SDL_VideoDevice *SDL_GetVideoDevice(void);
 extern int SDL_AddBasicVideoDisplay(const SDL_DisplayMode * desktop_mode);
--- a/src/video/SDL_video.c	Fri Dec 13 09:48:12 2013 -0300
+++ b/src/video/SDL_video.c	Sat Dec 14 20:18:43 2013 -0300
@@ -86,6 +86,9 @@
 #if SDL_VIDEO_DRIVER_DUMMY
     &DUMMY_bootstrap,
 #endif
+#if SDL_VIDEO_DRIVER_WAYLAND
+    &Wayland_bootstrap,
+#endif
     NULL
 };
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/video/wayland/SDL_waylandevents.c	Sat Dec 14 20:18:43 2013 -0300
@@ -0,0 +1,381 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include "SDL_config.h"
+
+#include "SDL_stdinc.h"
+#include "SDL_assert.h"
+
+#include "../../events/SDL_sysevents.h"
+#include "../../events/SDL_events_c.h"
+#include "../../events/scancodes_xfree86.h"
+
+#include "SDL_waylandvideo.h"
+#include "SDL_waylandevents_c.h"
+#include "SDL_waylandwindow.h"
+
+#include <linux/input.h>
+#include <sys/select.h>
+#include <sys/mman.h>
+#include <poll.h>
+#include <errno.h>
+#include <unistd.h>
+#include <xkbcommon/xkbcommon.h>
+
+struct SDL_WaylandInput {
+    SDL_VideoData *display;
+    struct wl_seat *seat;
+    struct wl_pointer *pointer;
+    struct wl_keyboard *keyboard;
+    SDL_WindowData *pointer_focus;
+    SDL_WindowData *keyboard_focus;
+
+    struct {
+        struct xkb_keymap *keymap;
+        struct xkb_state *state;
+    } xkb;
+};
+
+void
+Wayland_PumpEvents(_THIS)
+{
+    SDL_VideoData *d = _this->driverdata;
+    struct pollfd pfd[1];
+
+    pfd[0].fd = wl_display_get_fd(d->display);
+    pfd[0].events = POLLIN;
+    poll(pfd, 1, 0);
+
+    if (pfd[0].revents & POLLIN)
+        wl_display_dispatch(d->display);
+    else
+        wl_display_dispatch_pending(d->display);
+}
+
+static void
+pointer_handle_enter(void *data, struct wl_pointer *pointer,
+                     uint32_t serial, struct wl_surface *surface,
+                     wl_fixed_t sx_w, wl_fixed_t sy_w)
+{
+    struct SDL_WaylandInput *input = data;
+    SDL_WindowData *window;
+
+    if (!surface) {
+        /* enter event for a window we've just destroyed */
+        return;
+    }
+
+    input->pointer_focus = wl_surface_get_user_data(surface);
+    window = input->pointer_focus;
+    SDL_SetMouseFocus(window->sdlwindow);
+}
+
+static void
+pointer_handle_leave(void *data, struct wl_pointer *pointer,
+                     uint32_t serial, struct wl_surface *surface)
+{
+    struct SDL_WaylandInput *input = data;
+
+    SDL_SetMouseFocus(NULL);
+    input->pointer_focus = NULL;
+}
+
+static void
+pointer_handle_motion(void *data, struct wl_pointer *pointer,
+                      uint32_t time, wl_fixed_t sx_w, wl_fixed_t sy_w)
+{
+    struct SDL_WaylandInput *input = data;
+    SDL_WindowData *window = input->pointer_focus;
+    int sx = wl_fixed_to_int(sx_w);
+    int sy = wl_fixed_to_int(sy_w);
+
+    SDL_SendMouseMotion(window->sdlwindow, 0, 0, sx, sy);
+}
+
+static void
+pointer_handle_button(void *data, struct wl_pointer *pointer, uint32_t serial,
+                      uint32_t time, uint32_t button, uint32_t state_w)
+{
+    struct SDL_WaylandInput *input = data;
+    SDL_WindowData *window = input->pointer_focus;
+    enum wl_pointer_button_state state = state_w;
+    uint32_t sdl_button;
+
+    switch (button) {
+    case BTN_LEFT:
+        sdl_button = SDL_BUTTON_LEFT;
+        break;
+    case BTN_MIDDLE:
+        sdl_button = SDL_BUTTON_MIDDLE;
+        break;
+    case BTN_RIGHT:
+        sdl_button = SDL_BUTTON_RIGHT;
+        break;
+    case BTN_SIDE:
+        sdl_button = SDL_BUTTON_X1;
+        break;
+    case BTN_EXTRA:
+        sdl_button = SDL_BUTTON_X2;
+        break;
+    default:
+        return;
+    }
+
+    SDL_SendMouseButton(window->sdlwindow, 0,
+                        state ? SDL_PRESSED : SDL_RELEASED, sdl_button);
+}
+
+static void
+pointer_handle_axis(void *data, struct wl_pointer *pointer,
+                    uint32_t time, uint32_t axis, wl_fixed_t value)
+{
+    struct SDL_WaylandInput *input = data;
+    SDL_WindowData *window = input->pointer_focus;
+    enum wl_pointer_axis a = axis;
+    int x, y;
+
+    switch (a) {
+    case WL_POINTER_AXIS_VERTICAL_SCROLL:
+        x = 0;
+        y = wl_fixed_to_int(value);
+        break;
+    case WL_POINTER_AXIS_HORIZONTAL_SCROLL:
+        x = wl_fixed_to_int(value);
+        y = 0;
+        break;
+    default:
+        return;
+    }
+
+    SDL_SendMouseWheel(window->sdlwindow, 0, x, y);
+}
+
+static const struct wl_pointer_listener pointer_listener = {
+    pointer_handle_enter,
+    pointer_handle_leave,
+    pointer_handle_motion,
+    pointer_handle_button,
+    pointer_handle_axis,
+};
+
+static void
+keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard,
+                       uint32_t format, int fd, uint32_t size)
+{
+    struct SDL_WaylandInput *input = data;
+    char *map_str;
+
+    if (!data) {
+        close(fd);
+        return;
+    }
+
+    if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) {
+        close(fd);
+        return;
+    }
+
+    map_str = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
+    if (map_str == MAP_FAILED) {
+        close(fd);
+        return;
+    }
+
+    input->xkb.keymap = xkb_map_new_from_string(input->display->xkb_context,
+                                                map_str,
+                                                XKB_KEYMAP_FORMAT_TEXT_V1,
+                                                0);
+    munmap(map_str, size);
+    close(fd);
+
+    if (!input->xkb.keymap) {
+        fprintf(stderr, "failed to compile keymap\n");
+        return;
+    }
+
+    input->xkb.state = xkb_state_new(input->xkb.keymap);
+    if (!input->xkb.state) {
+        fprintf(stderr, "failed to create XKB state\n");
+        xkb_map_unref(input->xkb.keymap);
+        input->xkb.keymap = NULL;
+        return;
+    }
+}
+
+static void
+keyboard_handle_enter(void *data, struct wl_keyboard *keyboard,
+                      uint32_t serial, struct wl_surface *surface,
+                      struct wl_array *keys)
+{
+    struct SDL_WaylandInput *input = data;
+    SDL_WindowData *window = wl_surface_get_user_data(surface);
+
+    input->keyboard_focus = window;
+    window->keyboard_device = input;
+    SDL_SetKeyboardFocus(window->sdlwindow);
+}
+
+static void
+keyboard_handle_leave(void *data, struct wl_keyboard *keyboard,
+                      uint32_t serial, struct wl_surface *surface)
+{
+    SDL_SetKeyboardFocus(NULL);
+}
+
+static void
+keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
+                    uint32_t serial, uint32_t time, uint32_t key,
+                    uint32_t state_w)
+{
+    struct SDL_WaylandInput *input = data;
+    SDL_WindowData *window = input->keyboard_focus;
+    enum wl_keyboard_key_state state = state_w;
+    const xkb_keysym_t *syms;
+    uint32_t scancode;
+    char text[8];
+    int size;
+
+    if (key < SDL_arraysize(xfree86_scancode_table2)) {
+        scancode = xfree86_scancode_table2[key];
+
+        // TODO when do we get WL_KEYBOARD_KEY_STATE_REPEAT?
+        if (scancode != SDL_SCANCODE_UNKNOWN)
+            SDL_SendKeyboardKey(state == WL_KEYBOARD_KEY_STATE_PRESSED ?
+                                SDL_PRESSED : SDL_RELEASED, scancode);
+    }
+
+    if (!window || window->keyboard_device != input || !input->xkb.state)
+        return;
+
+    // TODO can this happen?
+    if (xkb_key_get_syms(input->xkb.state, key + 8, &syms) != 1)
+        return;
+
+    if (state) {
+        size = xkb_keysym_to_utf8(syms[0], text, sizeof text);
+
+        if (size > 0) {
+            text[size] = 0;
+            SDL_SendKeyboardText(text);
+        }
+    }
+}
+
+static void
+keyboard_handle_modifiers(void *data, struct wl_keyboard *keyboard,
+                          uint32_t serial, uint32_t mods_depressed,
+                          uint32_t mods_latched, uint32_t mods_locked,
+                          uint32_t group)
+{
+    struct SDL_WaylandInput *input = data;
+
+    xkb_state_update_mask(input->xkb.state, mods_depressed, mods_latched,
+                          mods_locked, 0, 0, group);
+}
+
+static const struct wl_keyboard_listener keyboard_listener = {
+    keyboard_handle_keymap,
+    keyboard_handle_enter,
+    keyboard_handle_leave,
+    keyboard_handle_key,
+    keyboard_handle_modifiers,
+};
+
+static void
+seat_handle_capabilities(void *data, struct wl_seat *seat,
+                         enum wl_seat_capability caps)
+{
+    struct SDL_WaylandInput *input = data;
+
+    if ((caps & WL_SEAT_CAPABILITY_POINTER) && !input->pointer) {
+        input->pointer = wl_seat_get_pointer(seat);
+        input->display->pointer = input->pointer;
+        wl_pointer_set_user_data(input->pointer, input);
+        wl_pointer_add_listener(input->pointer, &pointer_listener,
+                                input);
+    } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && input->pointer) {
+        wl_pointer_destroy(input->pointer);
+        input->pointer = NULL;
+    }
+
+    if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !input->keyboard) {
+        input->keyboard = wl_seat_get_keyboard(seat);
+        wl_keyboard_set_user_data(input->keyboard, input);
+        wl_keyboard_add_listener(input->keyboard, &keyboard_listener,
+                                 input);
+    } else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && input->keyboard) {
+        wl_keyboard_destroy(input->keyboard);
+        input->keyboard = NULL;
+    }
+}
+
+static const struct wl_seat_listener seat_listener = {
+    seat_handle_capabilities,
+};
+
+void
+Wayland_display_add_input(SDL_VideoData *d, uint32_t id)
+{
+    struct SDL_WaylandInput *input;
+
+    input = malloc(sizeof *input);
+    if (input == NULL)
+        return;
+
+    memset(input, 0, sizeof *input);
+    input->display = d;
+    input->seat = wl_registry_bind(d->registry, id, &wl_seat_interface, 1);
+
+    d->input = input;
+
+    wl_seat_add_listener(input->seat, &seat_listener, input);
+    wl_seat_set_user_data(input->seat, input);
+
+    wayland_schedule_write(d);
+}
+
+void Wayland_display_destroy_input(SDL_VideoData *d)
+{
+    struct SDL_WaylandInput *input = d->input;
+
+    if (!input)
+        return;
+
+    if (input->keyboard)
+        wl_keyboard_destroy(input->keyboard);
+
+    if (input->pointer)
+        wl_pointer_destroy(input->pointer);
+
+    if (input->seat)
+        wl_seat_destroy(input->seat);
+
+    if (input->xkb.state)
+        xkb_state_unref(input->xkb.state);
+
+    if (input->xkb.keymap)
+        xkb_map_unref(input->xkb.keymap);
+
+    free(input);
+    d->input = NULL;
+}
+
+/* vi: set ts=4 sw=4 expandtab: */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/video/wayland/SDL_waylandevents_c.h	Sat Dec 14 20:18:43 2013 -0300
@@ -0,0 +1,37 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include "SDL_config.h"
+
+#ifndef _SDL_waylandevents_h
+#define _SDL_waylandevents_h
+
+#include "SDL_waylandvideo.h"
+#include "SDL_waylandwindow.h"
+
+extern void Wayland_PumpEvents(_THIS);
+
+extern void Wayland_display_add_input(SDL_VideoData *d, uint32_t id);
+extern void Wayland_display_destroy_input(SDL_VideoData *d);
+
+#endif /* _SDL_waylandevents_h */
+
+/* vi: set ts=4 sw=4 expandtab: */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/video/wayland/SDL_waylandmouse.c	Sat Dec 14 20:18:43 2013 -0300
@@ -0,0 +1,407 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <limits.h>
+
+#include "../SDL_sysvideo.h"
+
+#include "SDL_config.h"
+#include "SDL_mouse.h"
+#include "../../events/SDL_mouse_c.h"
+#include "SDL_waylandvideo.h"
+#include "SDL_waylandevents_c.h"
+
+#include "SDL_assert.h"
+
+#if SDL_VIDEO_DRIVER_WAYLAND
+
+typedef struct {
+    struct wl_buffer   *buffer;
+    struct wl_surface  *surface;
+
+    int                hot_x, hot_y;
+
+    /* Either a preloaded cursor, or one we created ourselves */
+    struct wl_cursor   *cursor;
+    void               *shm_data;
+} Wayland_CursorData;
+
+static int
+wayland_create_tmp_file(off_t size)
+{
+    static const char template[] = "/sdl-shared-XXXXXX";
+    char *xdg_path;
+    char tmp_path[PATH_MAX];
+    int fd;
+
+    xdg_path = SDL_getenv("XDG_RUNTIME_DIR");
+    if (!xdg_path) {
+        errno = ENOENT;
+        return -1;
+    }
+
+    SDL_strlcpy(tmp_path, xdg_path, PATH_MAX);
+    SDL_strlcat(tmp_path, template, PATH_MAX);
+
+    fd = mkostemp(tmp_path, O_CLOEXEC);
+    if (fd < 0)
+        return -1;
+
+    if (ftruncate(fd, size) < 0) {
+        close(fd);
+        return -1;
+    }
+
+    return fd;
+}
+
+static void
+mouse_buffer_release(void *data, struct wl_buffer *buffer)
+{
+}
+
+static const struct wl_buffer_listener mouse_buffer_listener = {
+    mouse_buffer_release
+};
+
+static int
+create_buffer_from_shm(Wayland_CursorData *d,
+                       int width,
+                       int height,
+                       uint32_t format)
+{
+    SDL_VideoDevice *vd = SDL_GetVideoDevice();
+    SDL_VideoData *data = (SDL_VideoData *) vd->driverdata;
+
+    int stride = width * 4;
+    int size = stride * height;
+
+    int shm_fd;
+
+    shm_fd = wayland_create_tmp_file(size);
+    if (shm_fd < 0)
+    {
+        fprintf(stderr, "creating mouse cursor buffer failed!\n");
+        return -1;
+    }
+
+    d->shm_data = mmap(NULL,
+                       size,
+                       PROT_READ | PROT_WRITE,
+                       MAP_SHARED,
+                       shm_fd,
+                       0);
+    if (data == MAP_FAILED) {
+        d->shm_data = NULL;
+        fprintf (stderr, "mmap () failed\n");
+        close (shm_fd);
+    }
+
+    struct wl_shm_pool *shm_pool = wl_shm_create_pool(data->shm,
+                                                      shm_fd,
+                                                      size);
+    d->buffer = wl_shm_pool_create_buffer(shm_pool,
+                                          0,
+                                          width,
+                                          height,
+                                          stride,
+                                          format);
+    wl_buffer_add_listener(d->buffer,
+                           &mouse_buffer_listener,
+                           d);
+
+    wl_shm_pool_destroy (shm_pool);
+    close (shm_fd);
+
+    return 0;
+}
+
+static SDL_Cursor *
+Wayland_CreateCursor(SDL_Surface *surface, int hot_x, int hot_y)
+{
+    SDL_Cursor *cursor;
+
+    cursor = calloc(1, sizeof (*cursor));
+    if (cursor) {
+        SDL_VideoDevice *vd = SDL_GetVideoDevice ();
+        SDL_VideoData *wd = (SDL_VideoData *) vd->driverdata;
+        Wayland_CursorData *data = calloc (1, sizeof (Wayland_CursorData));
+        cursor->driverdata = (void *) data;
+
+        /* Assume ARGB8888 */
+        SDL_assert(surface->format->format == SDL_PIXELFORMAT_ARGB8888);
+        SDL_assert(surface->pitch == surface->w * 4);
+
+        /* Allocate shared memory buffer for this cursor */
+        if (create_buffer_from_shm (data,
+                                    surface->w,
+                                    surface->h,
+                                    WL_SHM_FORMAT_XRGB8888) < 0)
+        {
+            free (cursor->driverdata);
+            free (cursor);
+            return NULL;
+        }
+
+        SDL_memcpy(data->shm_data,
+                   surface->pixels,
+                   surface->h * surface->pitch);
+
+        data->surface = wl_compositor_create_surface(wd->compositor);
+        wl_surface_attach(data->surface,
+                          data->buffer,
+                          0,
+                          0);
+        wl_surface_damage(data->surface,
+                          0,
+                          0,
+                          surface->w,
+                          surface->h);
+        wl_surface_commit(data->surface);
+
+        data->hot_x = hot_x;
+        data->hot_y = hot_y;
+    }
+
+    return cursor;
+}
+
+static SDL_Cursor *
+CreateCursorFromWlCursor(SDL_VideoData *d, struct wl_cursor *wlcursor)
+{
+    SDL_Cursor *cursor;
+
+    cursor = calloc(1, sizeof (*cursor));
+    if (cursor) {
+        Wayland_CursorData *data = calloc (1, sizeof (Wayland_CursorData));
+        cursor->driverdata = (void *) data;
+
+        /* The wl_buffer here will be destroyed from wl_cursor_theme_destroy
+         * if we are fetching this from a wl_cursor_theme, so don't store a
+         * reference to it here */
+        data->buffer = NULL;
+        data->surface = wl_compositor_create_surface(d->compositor);
+        wl_surface_attach(data->surface,
+                          wl_cursor_image_get_buffer(wlcursor->images[0]),
+                          0,
+                          0);
+        wl_surface_damage(data->surface,
+                          0,
+                          0,
+                          wlcursor->images[0]->width,
+                          wlcursor->images[0]->height);
+        wl_surface_commit(data->surface);
+        data->hot_x = wlcursor->images[0]->hotspot_x;
+        data->hot_y = wlcursor->images[0]->hotspot_y;
+        data->cursor= wlcursor;
+    } else {
+        SDL_OutOfMemory ();
+    }
+
+    return cursor;
+}
+
+static SDL_Cursor *
+Wayland_CreateDefaultCursor()
+{
+    SDL_VideoDevice *device = SDL_GetVideoDevice();
+    SDL_VideoData *data = device->driverdata;
+
+    return CreateCursorFromWlCursor (data,
+                                     wl_cursor_theme_get_cursor(data->cursor_theme,
+                                                                "left_ptr"));
+}
+
+static SDL_Cursor *
+Wayland_CreateSystemCursor(SDL_SystemCursor id)
+{
+    SDL_VideoDevice *vd = SDL_GetVideoDevice();
+    SDL_VideoData *d = vd->driverdata;
+
+    struct wl_cursor *cursor = NULL;
+
+    switch(id)
+    {
+    default:
+        SDL_assert(0);
+        return NULL;
+    case SDL_SYSTEM_CURSOR_ARROW:
+        cursor = wl_cursor_theme_get_cursor(d->cursor_theme, "left_ptr");
+        break;
+    case SDL_SYSTEM_CURSOR_IBEAM:
+        cursor = wl_cursor_theme_get_cursor(d->cursor_theme, "xterm");
+        break;
+    case SDL_SYSTEM_CURSOR_WAIT:
+        cursor = wl_cursor_theme_get_cursor(d->cursor_theme, "wait");
+        break;
+    case SDL_SYSTEM_CURSOR_CROSSHAIR:
+        cursor = wl_cursor_theme_get_cursor(d->cursor_theme, "hand1");
+        break;
+    case SDL_SYSTEM_CURSOR_WAITARROW:
+        cursor = wl_cursor_theme_get_cursor(d->cursor_theme, "wait");
+        break;
+    case SDL_SYSTEM_CURSOR_SIZENWSE:
+        cursor = wl_cursor_theme_get_cursor(d->cursor_theme, "hand1");
+        break;
+    case SDL_SYSTEM_CURSOR_SIZENESW:
+        cursor = wl_cursor_theme_get_cursor(d->cursor_theme, "hand1");
+        break;
+    case SDL_SYSTEM_CURSOR_SIZEWE:
+        cursor = wl_cursor_theme_get_cursor(d->cursor_theme, "hand1");
+        break;
+    case SDL_SYSTEM_CURSOR_SIZENS:
+        cursor = wl_cursor_theme_get_cursor(d->cursor_theme, "hand1");
+        break;
+    case SDL_SYSTEM_CURSOR_SIZEALL:
+        cursor = wl_cursor_theme_get_cursor(d->cursor_theme, "hand1");
+        break;
+    case SDL_SYSTEM_CURSOR_NO:
+        cursor = wl_cursor_theme_get_cursor(d->cursor_theme, "xterm");
+        break;
+    case SDL_SYSTEM_CURSOR_HAND:
+        cursor = wl_cursor_theme_get_cursor(d->cursor_theme, "hand1");
+        break;
+    }
+
+    SDL_Cursor *sdl_cursor = CreateCursorFromWlCursor (d, cursor);
+
+    return sdl_cursor;
+}
+
+static void
+Wayland_FreeCursor(SDL_Cursor *cursor)
+{
+    if (!cursor)
+        return;
+
+    Wayland_CursorData *d = cursor->driverdata;
+
+    /* Probably not a cursor we own */
+    if (!d)
+        return;
+
+    if (d->buffer)
+        wl_buffer_destroy(d->buffer);
+
+    if (d->surface)
+        wl_surface_destroy(d->surface);
+
+    /* Not sure what's meant to happen to shm_data */
+    free (cursor->driverdata);
+    SDL_free(cursor);
+}
+
+static int
+Wayland_ShowCursor(SDL_Cursor *cursor)
+{
+    SDL_VideoDevice *vd = SDL_GetVideoDevice();
+    SDL_VideoData *d = vd->driverdata;
+
+    struct wl_pointer *pointer = d->pointer;
+
+    if (!pointer)
+        return -1;
+
+    if (cursor)
+    {
+        Wayland_CursorData *data = cursor->driverdata;
+
+        wl_pointer_set_cursor (pointer, 0,
+                               data->surface,
+                               data->hot_x,
+                               data->hot_y);
+    }
+    else
+    {
+        wl_pointer_set_cursor (pointer, 0,
+                               NULL,
+                               0,
+                               0);
+    }
+    
+    return 0;
+}
+
+static void
+Wayland_WarpMouse(SDL_Window *window, int x, int y)
+{
+    SDL_Unsupported();
+    return;
+}
+
+static int
+Wayland_SetRelativeMouseMode(SDL_bool enabled)
+{
+    SDL_Unsupported();
+    return -1;
+}
+
+void
+Wayland_InitMouse(void)
+{
+    SDL_Mouse *mouse = SDL_GetMouse();
+
+    mouse->CreateCursor = Wayland_CreateCursor;
+    mouse->CreateSystemCursor = Wayland_CreateSystemCursor;
+    mouse->ShowCursor = Wayland_ShowCursor;
+    mouse->FreeCursor = Wayland_FreeCursor;
+    mouse->WarpMouse = Wayland_WarpMouse;
+    mouse->SetRelativeMouseMode = Wayland_SetRelativeMouseMode;
+
+    SDL_SetDefaultCursor(Wayland_CreateDefaultCursor());
+}
+
+void
+Wayland_FiniMouse(void)
+{
+    /* This effectively assumes that nobody else
+     * touches SDL_Mouse which is effectively
+     * a singleton */
+
+    SDL_Mouse *mouse = SDL_GetMouse();
+
+    /* Free the current cursor if not the same pointer as
+     * the default cursor */
+    if (mouse->def_cursor != mouse->cur_cursor)
+        Wayland_FreeCursor (mouse->cur_cursor);
+
+    Wayland_FreeCursor (mouse->def_cursor);
+    mouse->def_cursor = NULL;
+    mouse->cur_cursor = NULL;
+
+    mouse->CreateCursor =  NULL;
+    mouse->CreateSystemCursor = NULL;
+    mouse->ShowCursor = NULL;
+    mouse->FreeCursor = NULL;
+    mouse->WarpMouse = NULL;
+    mouse->SetRelativeMouseMode = NULL;
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/video/wayland/SDL_waylandmouse.h	Sat Dec 14 20:18:43 2013 -0300
@@ -0,0 +1,31 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include "SDL_config.h"
+#include "SDL_mouse.h"
+#include "SDL_waylandvideo.h"
+
+#if SDL_VIDEO_DRIVER_WAYLAND
+
+extern void Wayland_InitMouse(void);
+extern void Wayland_FiniMouse(void);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/video/wayland/SDL_waylandopengles.c	Sat Dec 14 20:18:43 2013 -0300
@@ -0,0 +1,90 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+#include "SDL_config.h"
+
+#if SDL_VIDEO_DRIVER_WAYLAND && SDL_VIDEO_OPENGL_EGL
+
+#include "SDL_waylandvideo.h"
+#include "SDL_waylandopengles.h"
+#include "SDL_waylandwindow.h"
+#include "SDL_waylandevents_c.h"
+
+/* EGL implementation of SDL OpenGL ES support */
+
+int
+Wayland_GLES_LoadLibrary(_THIS, const char *path) {
+    int ret;
+    SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
+    
+    ret = SDL_EGL_LoadLibrary(_this, path, (NativeDisplayType) data->display);
+
+    Wayland_PumpEvents(_this);
+    wayland_schedule_write(data);
+    
+    return ret;
+}
+
+
+SDL_GLContext
+Wayland_GLES_CreateContext(_THIS, SDL_Window * window)
+{
+    SDL_GLContext context;
+    context = SDL_EGL_CreateContext(_this, ((SDL_WindowData *) window->driverdata)->egl_surface);
+    wayland_schedule_write(_this->driverdata);
+    
+    return context;
+}
+
+void
+Wayland_GLES_SwapWindow(_THIS, SDL_Window *window)
+{
+    SDL_EGL_SwapBuffers(_this, ((SDL_WindowData *) window->driverdata)->egl_surface);
+    wayland_schedule_write(_this->driverdata);
+}
+
+
+int
+Wayland_GLES_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context)
+{
+    int ret;
+    
+    if (window && context) {
+        ret = SDL_EGL_MakeCurrent(_this, ((SDL_WindowData *) window->driverdata)->egl_surface, context);
+    }
+    else {
+        ret = SDL_EGL_MakeCurrent(_this, NULL, NULL);
+    }
+    
+    wayland_schedule_write(_this->driverdata);
+    
+    return ret;
+}
+
+void 
+Wayland_GLES_DeleteContext(_THIS, SDL_GLContext context)
+{
+    SDL_EGL_DeleteContext(_this, context);
+    wayland_schedule_write(_this->driverdata);
+}
+
+#endif /* SDL_VIDEO_DRIVER_WAYLAND && SDL_VIDEO_OPENGL_EGL */
+
+/* vi: set ts=4 sw=4 expandtab: */
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/video/wayland/SDL_waylandopengles.h	Sat Dec 14 20:18:43 2013 -0300
@@ -0,0 +1,46 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+#include "SDL_config.h"
+
+#ifndef _SDL_waylandopengles_h
+#define _SDL_waylandopengles_h
+
+#include "../SDL_sysvideo.h"
+#include "../SDL_egl_c.h"
+
+typedef struct SDL_PrivateGLESData
+{
+} SDL_PrivateGLESData;
+
+/* OpenGLES functions */
+#define Wayland_GLES_GetAttribute SDL_EGL_GetAttribute
+#define Wayland_GLES_GetProcAddress SDL_EGL_GetProcAddress
+#define Wayland_GLES_UnloadLibrary SDL_EGL_UnloadLibrary
+#define Wayland_GLES_SetSwapInterval SDL_EGL_SetSwapInterval
+#define Wayland_GLES_GetSwapInterval SDL_EGL_GetSwapInterval
+
+extern int Wayland_GLES_LoadLibrary(_THIS, const char *path);
+extern SDL_GLContext Wayland_GLES_CreateContext(_THIS, SDL_Window * window);
+extern void Wayland_GLES_SwapWindow(_THIS, SDL_Window * window);
+extern int Wayland_GLES_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context);
+extern void Wayland_GLES_DeleteContext(_THIS, SDL_GLContext context);
+
+#endif /* _SDL_waylandopengles_h */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/video/wayland/SDL_waylandvideo.c	Sat Dec 14 20:18:43 2013 -0300
@@ -0,0 +1,365 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include "SDL_config.h"
+
+#include "SDL_video.h"
+#include "SDL_mouse.h"
+#include "../../events/SDL_events_c.h"
+
+#include "SDL_waylandvideo.h"
+#include "SDL_waylandevents_c.h"
+#include "SDL_waylandwindow.h"
+#include "SDL_waylandopengles.h"
+#include "SDL_waylandmouse.h"
+
+#include <fcntl.h>
+#include <xkbcommon/xkbcommon.h>
+
+#define WAYLANDVID_DRIVER_NAME "wayland"
+
+struct wayland_mode {
+    SDL_DisplayMode mode;
+    struct wl_list link;
+};
+
+/* Initialization/Query functions */
+static int
+Wayland_VideoInit(_THIS);
+
+static void
+Wayland_GetDisplayModes(_THIS, SDL_VideoDisplay *sdl_display);
+static int
+Wayland_SetDisplayMode(_THIS, SDL_VideoDisplay *display, SDL_DisplayMode *mode);
+
+static void
+Wayland_VideoQuit(_THIS);
+
+/* Wayland driver bootstrap functions */
+static int
+Wayland_Available(void)
+{
+    struct wl_display *display = NULL;
+
+    display = wl_display_connect(NULL);
+    if (display != NULL) {
+        wl_display_disconnect(display);
+    }
+
+    return (display != NULL);
+}
+
+static void
+Wayland_DeleteDevice(SDL_VideoDevice *device)
+{
+    SDL_free(device);
+}
+
+static SDL_VideoDevice *
+Wayland_CreateDevice(int devindex)
+{
+    SDL_VideoDevice *device;
+
+    /* Initialize all variables that we clean on shutdown */
+    device = SDL_calloc(1, sizeof(SDL_VideoDevice));
+    if (!device) {
+        SDL_OutOfMemory();
+        return NULL;
+    }
+
+    /* Set the function pointers */
+    device->VideoInit = Wayland_VideoInit;
+    device->VideoQuit = Wayland_VideoQuit;
+    device->SetDisplayMode = Wayland_SetDisplayMode;
+    device->GetDisplayModes = Wayland_GetDisplayModes;
+    device->GetWindowWMInfo = Wayland_GetWindowWMInfo;
+
+    device->PumpEvents = Wayland_PumpEvents;
+
+    device->GL_SwapWindow = Wayland_GLES_SwapWindow;
+    device->GL_GetSwapInterval = Wayland_GLES_GetSwapInterval;
+    device->GL_SetSwapInterval = Wayland_GLES_SetSwapInterval;
+    device->GL_MakeCurrent = Wayland_GLES_MakeCurrent;
+    device->GL_CreateContext = Wayland_GLES_CreateContext;
+    device->GL_LoadLibrary = Wayland_GLES_LoadLibrary;
+    device->GL_UnloadLibrary = Wayland_GLES_UnloadLibrary;
+    device->GL_GetProcAddress = Wayland_GLES_GetProcAddress;
+    device->GL_DeleteContext = Wayland_GLES_DeleteContext;
+
+    device->CreateWindow = Wayland_CreateWindow;
+    device->ShowWindow = Wayland_ShowWindow;
+    device->SetWindowFullscreen = Wayland_SetWindowFullscreen;
+    device->SetWindowSize = Wayland_SetWindowSize;
+    device->DestroyWindow = Wayland_DestroyWindow;
+
+    device->free = Wayland_DeleteDevice;
+
+    return device;
+}
+
+VideoBootStrap Wayland_bootstrap = {
+    WAYLANDVID_DRIVER_NAME, "SDL Wayland video driver",
+    Wayland_Available, Wayland_CreateDevice
+};
+
+static void
+wayland_add_mode(SDL_VideoData *d, SDL_DisplayMode m)
+{
+    struct wayland_mode *mode;
+
+    /* Check for duplicate mode */
+    wl_list_for_each(mode, &d->modes_list, link)
+        if (mode->mode.w == m.w && mode->mode.h == m.h &&
+	    mode->mode.refresh_rate == m.refresh_rate)
+	    return;
+
+    /* Add new mode to the list */
+    mode = SDL_calloc(1, sizeof *mode);
+
+    if (!mode)
+	return;
+
+    mode->mode = m;
+    wl_list_insert(&d->modes_list, &mode->link);
+}
+
+static void
+display_handle_geometry(void *data,
+                        struct wl_output *output,
+                        int x, int y,
+                        int physical_width,
+                        int physical_height,
+                        int subpixel,
+                        const char *make,
+                        const char *model,
+                        int transform)
+
+{
+    SDL_VideoData *d = data;
+
+    d->screen_allocation.x = x;
+    d->screen_allocation.y = y;
+}
+
+static void
+display_handle_mode(void *data,
+                    struct wl_output *wl_output,
+                    uint32_t flags,
+                    int width,
+                    int height,
+                    int refresh)
+{
+    SDL_VideoData *d = data;
+    SDL_DisplayMode mode;
+
+    SDL_zero(mode);
+    mode.w = width;
+    mode.h = height;
+    mode.refresh_rate = refresh / 1000;
+
+    wayland_add_mode(d, mode);
+
+    if (flags & WL_OUTPUT_MODE_CURRENT) {
+        d->screen_allocation.width = width;
+        d->screen_allocation.height = height;
+    }
+}
+
+static const struct wl_output_listener output_listener = {
+    display_handle_geometry,
+    display_handle_mode
+};
+
+static void
+shm_handle_format(void *data,
+                  struct wl_shm *shm,
+                  uint32_t format)
+{
+    SDL_VideoData *d = data;
+
+    d->shm_formats |= (1 << format);
+}
+
+static const struct wl_shm_listener shm_listener = {
+    shm_handle_format
+};
+
+static void
+display_handle_global(void *data, struct wl_registry *registry, uint32_t id,
+					const char *interface, uint32_t version)
+{
+    SDL_VideoData *d = data;
+
+    if (strcmp(interface, "wl_compositor") == 0) {
+        d->compositor = wl_registry_bind(d->registry, id, &wl_compositor_interface, 1);
+    } else if (strcmp(interface, "wl_output") == 0) {
+        d->output = wl_registry_bind(d->registry, id, &wl_output_interface, 1);
+        wl_output_add_listener(d->output, &output_listener, d);
+    } else if (strcmp(interface, "wl_seat") == 0) {
+        Wayland_display_add_input(d, id);
+    } else if (strcmp(interface, "wl_shell") == 0) {
+        d->shell = wl_registry_bind(d->registry, id, &wl_shell_interface, 1);
+    } else if (strcmp(interface, "wl_shm") == 0) {
+        d->shm = wl_registry_bind(registry, id, &wl_shm_interface, 1);
+        d->cursor_theme = wl_cursor_theme_load(NULL, 32, d->shm);
+        d->default_cursor = wl_cursor_theme_get_cursor(d->cursor_theme, "left_ptr");
+        wl_shm_add_listener(d->shm, &shm_listener, d);
+    }
+}
+
+static const struct wl_registry_listener registry_listener = {
+	display_handle_global
+};
+
+int
+Wayland_VideoInit(_THIS)
+{
+    SDL_VideoData *data;
+
+    data = malloc(sizeof *data);
+    if (data == NULL)
+        return 0;
+    memset(data, 0, sizeof *data);
+
+    _this->driverdata = data;
+
+    wl_list_init(&data->modes_list);
+    
+    data->display = wl_display_connect(NULL);
+    if (data->display == NULL) {
+        SDL_SetError("Failed to connect to a Wayland display");
+        return 0;
+    }
+
+    data->registry = wl_display_get_registry(data->display);
+    wl_registry_add_listener(data->registry, &registry_listener, data);
+
+    while (data->screen_allocation.width == 0)
+        wl_display_dispatch(data->display);
+
+    data->xkb_context = xkb_context_new(0);
+    if (!data->xkb_context) {
+        SDL_SetError("Failed to create XKB context");
+        return 0;
+    }
+
+    SDL_VideoDisplay display;
+    SDL_DisplayMode mode;
+
+    /* Use a fake 32-bpp desktop mode */
+    mode.format = SDL_PIXELFORMAT_RGB888;
+    mode.w = data->screen_allocation.width;
+    mode.h = data->screen_allocation.height;
+    mode.refresh_rate = 0;
+    mode.driverdata = NULL;
+    wayland_add_mode(data, mode);
+    SDL_zero(display);
+    display.desktop_mode = mode;
+    display.current_mode = mode;
+    display.driverdata = NULL;
+    SDL_AddVideoDisplay(&display);
+
+    Wayland_InitMouse ();
+
+    wayland_schedule_write(data);
+
+    return 0;
+}
+
+static void
+Wayland_GetDisplayModes(_THIS, SDL_VideoDisplay *sdl_display)
+{
+    SDL_VideoData *data = _this->driverdata;
+    SDL_DisplayMode mode;
+    struct wayland_mode *m;
+
+    Wayland_PumpEvents(_this);
+
+    wl_list_for_each(m, &data->modes_list, link) {
+        m->mode.format = SDL_PIXELFORMAT_RGB888;
+        SDL_AddDisplayMode(sdl_display, &m->mode);
+        m->mode.format = SDL_PIXELFORMAT_RGBA8888;
+        SDL_AddDisplayMode(sdl_display, &m->mode);
+    }
+
+    mode.w = data->screen_allocation.width;
+    mode.h = data->screen_allocation.height;
+    mode.refresh_rate = 0;
+    mode.driverdata = NULL;
+
+    mode.format = SDL_PIXELFORMAT_RGB888;
+    SDL_AddDisplayMode(sdl_display, &mode);
+    mode.format = SDL_PIXELFORMAT_RGBA8888;
+    SDL_AddDisplayMode(sdl_display, &mode);
+}
+
+static int
+Wayland_SetDisplayMode(_THIS, SDL_VideoDisplay *display, SDL_DisplayMode *mode)
+{
+    return 0;
+}
+
+void
+Wayland_VideoQuit(_THIS)
+{
+    SDL_VideoData *data = _this->driverdata;
+    struct wayland_mode *t, *m;
+
+    Wayland_FiniMouse ();
+
+    if (data->output)
+        wl_output_destroy(data->output);
+
+    Wayland_display_destroy_input(data);
+
+    if (data->xkb_context) {
+        xkb_context_unref(data->xkb_context);
+        data->xkb_context = NULL;
+    }
+
+    if (data->shm)
+        wl_shm_destroy(data->shm);
+
+    if (data->cursor_theme)
+        wl_cursor_theme_destroy(data->cursor_theme);
+
+    if (data->shell)
+        wl_shell_destroy(data->shell);
+
+    if (data->compositor)
+        wl_compositor_destroy(data->compositor);
+
+    if (data->display) {
+        wl_display_flush(data->display);
+        wl_display_disconnect(data->display);
+    }
+    
+    wl_list_for_each_safe(m, t, &data->modes_list, link) {
+        wl_list_remove(&m->link);
+        free(m);
+    }
+
+
+    free(data);
+    _this->driverdata = NULL;
+}
+
+/* vi: set ts=4 sw=4 expandtab: */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/video/wayland/SDL_waylandvideo.h	Sat Dec 14 20:18:43 2013 -0300
@@ -0,0 +1,71 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include "SDL_config.h"
+
+#ifndef _SDL_waylandvideo_h
+#define _SDL_waylandvideo_h
+
+#include <wayland-client.h>
+#include <wayland-cursor.h>
+#include <wayland-egl.h>
+
+#include <EGL/egl.h>
+
+struct xkb_context;
+struct SDL_WaylandInput;
+
+typedef struct {
+    struct wl_display *display;
+    struct wl_registry *registry;
+    struct wl_compositor *compositor;
+    struct wl_output *output;
+    struct wl_shm *shm;
+    struct wl_cursor_theme *cursor_theme;
+    struct wl_cursor *default_cursor;
+    struct wl_pointer *pointer;
+    struct wl_shell *shell;
+
+    struct {
+        int32_t x, y, width, height;
+    } screen_allocation;
+
+    struct wl_list modes_list;
+
+    EGLDisplay edpy;
+    EGLContext context;
+    EGLConfig econf;
+
+    struct xkb_context *xkb_context;
+    struct SDL_WaylandInput *input;
+
+    uint32_t shm_formats;
+} SDL_VideoData;
+
+static inline void
+wayland_schedule_write(SDL_VideoData *data)
+{
+    wl_display_flush(data->display);
+}
+
+#endif /* _SDL_nullvideo_h */
+
+/* vi: set ts=4 sw=4 expandtab: */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/video/wayland/SDL_waylandwindow.c	Sat Dec 14 20:18:43 2013 -0300
@@ -0,0 +1,192 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include "SDL_config.h"
+
+#include "../SDL_sysvideo.h"
+#include "../../events/SDL_windowevents_c.h"
+#include "../SDL_egl_c.h"
+#include "SDL_waylandwindow.h"
+#include "SDL_waylandvideo.h"
+
+static void
+handle_ping(void *data, struct wl_shell_surface *shell_surface,
+            uint32_t serial)
+{
+    wl_shell_surface_pong(shell_surface, serial);
+}
+
+static void
+handle_configure(void *data, struct wl_shell_surface *shell_surface,
+                 uint32_t edges, int32_t width, int32_t height)
+{
+}
+
+static void
+handle_popup_done(void *data, struct wl_shell_surface *shell_surface)
+{
+}
+
+static const struct wl_shell_surface_listener shell_surface_listener = {
+    handle_ping,
+    handle_configure,
+    handle_popup_done
+};
+
+SDL_bool
+Wayland_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
+{
+    SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
+
+    info->info.wl.display = data->waylandData->display;
+    info->info.wl.surface = data->surface;
+    info->info.wl.shell_surface = data->shell_surface;
+    info->subsystem = SDL_SYSWM_WAYLAND;
+
+    return SDL_TRUE;
+}
+
+void Wayland_ShowWindow(_THIS, SDL_Window *window)
+{
+    SDL_WindowData *wind = window->driverdata;
+
+    if (window->flags & SDL_WINDOW_FULLSCREEN)
+        wl_shell_surface_set_fullscreen(wind->shell_surface,
+                                        WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT,
+                                        0, NULL);
+    else
+        wl_shell_surface_set_toplevel(wind->shell_surface);
+
+    wayland_schedule_write(_this->driverdata);
+}
+
+void
+Wayland_SetWindowFullscreen(_THIS, SDL_Window * window,
+                            SDL_VideoDisplay * _display, SDL_bool fullscreen)
+{
+    SDL_WindowData *wind = window->driverdata;
+
+    if (fullscreen)
+        wl_shell_surface_set_fullscreen(wind->shell_surface,
+                                        WL_SHELL_SURFACE_FULLSCREEN_METHOD_SCALE,
+                                        0, NULL);
+    else
+        wl_shell_surface_set_toplevel(wind->shell_surface);
+
+    wayland_schedule_write(_this->driverdata);
+}
+
+int Wayland_CreateWindow(_THIS, SDL_Window *window)
+{
+    SDL_WindowData *data;
+    SDL_VideoData *c;
+    struct wl_region *region;
+
+    data = calloc(1, sizeof *data);
+    if (data == NULL)
+        return 0;
+
+    c = _this->driverdata;
+    window->driverdata = data;
+
+    if (!(window->flags & SDL_WINDOW_OPENGL)) {
+        SDL_GL_LoadLibrary(NULL);
+        window->flags |= SDL_WINDOW_OPENGL;
+    }
+
+    if (window->x == SDL_WINDOWPOS_UNDEFINED) {
+        window->x = 0;
+    }
+    if (window->y == SDL_WINDOWPOS_UNDEFINED) {
+        window->y = 0;
+    }
+
+    data->waylandData = c;
+    data->sdlwindow = window;
+
+    data->surface =
+        wl_compositor_create_surface(c->compositor);
+    wl_surface_set_user_data(data->surface, data);
+    data->shell_surface = wl_shell_get_shell_surface(c->shell,
+                                                     data->surface);
+    data->egl_window = wl_egl_window_create(data->surface,
+                                            window->w, window->h);
+
+    /* Create the GLES window surface */
+    data->egl_surface = SDL_EGL_CreateSurface(_this, (NativeWindowType) data->egl_window);
+    
+    if (data->egl_surface == EGL_NO_SURFACE) {
+        SDL_SetError("failed to create a window surface");
+        return -1;
+    }
+
+    if (data->shell_surface) {
+        wl_shell_surface_set_user_data(data->shell_surface, data);
+        wl_shell_surface_add_listener(data->shell_surface,
+                                      &shell_surface_listener, data);
+    }
+
+    region = wl_compositor_create_region(c->compositor);
+    wl_region_add(region, 0, 0, window->w, window->h);
+    wl_surface_set_opaque_region(data->surface, region);
+    wl_region_destroy(region);
+
+    wayland_schedule_write(c);
+
+    return 0;
+}
+
+void Wayland_SetWindowSize(_THIS, SDL_Window * window)
+{
+    SDL_VideoData *data = _this->driverdata;
+    SDL_WindowData *wind = window->driverdata;
+    struct wl_region *region;
+
+    wl_egl_window_resize(wind->egl_window, window->w, window->h, 0, 0);
+
+    region = wl_compositor_create_region(data->compositor);
+    wl_region_add(region, 0, 0, window->w, window->h);
+    wl_surface_set_opaque_region(wind->surface, region);
+    wl_region_destroy(region);
+}
+
+void Wayland_DestroyWindow(_THIS, SDL_Window *window)
+{
+    SDL_VideoData *data = _this->driverdata;
+    SDL_WindowData *wind = window->driverdata;
+
+    window->driverdata = NULL;
+
+    if (data) {
+        SDL_EGL_DestroySurface(_this, wind->egl_surface);
+        wl_egl_window_destroy(wind->egl_window);
+
+        if (wind->shell_surface)
+            wl_shell_surface_destroy(wind->shell_surface);
+
+        wl_surface_destroy(wind->surface);
+
+        SDL_free(wind);
+        wayland_schedule_write(data);
+    }
+}
+
+/* vi: set ts=4 sw=4 expandtab: */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/video/wayland/SDL_waylandwindow.h	Sat Dec 14 20:18:43 2013 -0300
@@ -0,0 +1,58 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include "SDL_config.h"
+
+#ifndef _SDL_waylandwindow_h
+#define _SDL_waylandwindow_h
+
+#include "../SDL_sysvideo.h"
+#include "SDL_syswm.h"
+
+#include "SDL_waylandvideo.h"
+
+struct SDL_WaylandInput;
+
+typedef struct {
+    SDL_Window *sdlwindow;
+    SDL_VideoData *waylandData;
+    struct wl_surface *surface;
+    struct wl_shell_surface *shell_surface;
+    struct wl_egl_window *egl_window;
+    struct SDL_WaylandInput *keyboard_device;
+
+    EGLSurface egl_surface;
+} SDL_WindowData;
+
+extern void Wayland_ShowWindow(_THIS, SDL_Window *window);
+extern void Wayland_SetWindowFullscreen(_THIS, SDL_Window * window,
+                                        SDL_VideoDisplay * _display,
+                                        SDL_bool fullscreen);
+extern int Wayland_CreateWindow(_THIS, SDL_Window *window);
+extern void Wayland_SetWindowSize(_THIS, SDL_Window * window);
+extern void Wayland_DestroyWindow(_THIS, SDL_Window *window);
+
+extern SDL_bool
+Wayland_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info);
+
+#endif /* _SDL_waylandwindow_h */
+
+/* vi: set ts=4 sw=4 expandtab: */
--- a/test/Makefile.in	Fri Dec 13 09:48:12 2013 -0300
+++ b/test/Makefile.in	Sat Dec 14 20:18:43 2013 -0300
@@ -128,13 +128,13 @@
 	$(CC) -o $@ $^ $(CFLAGS) $(LIBS) @MATHLIB@
  
 testgl2$(EXE): $(srcdir)/testgl2.c
-	$(CC) -o $@ $^ $(CFLAGS) $(LIBS) @GLLIB@ @MATHLIB@
+	$(CC) -o $@ $^ $(CFLAGS) $(LIBS) @MATHLIB@
 
 testgles$(EXE): $(srcdir)/testgles.c
 	$(CC) -o $@ $^ $(CFLAGS) $(LIBS) @GLESLIB@ @MATHLIB@
 
 testgles2$(EXE): $(srcdir)/testgles2.c
-	$(CC) -o $@ $^ $(CFLAGS) $(LIBS) @GLES2LIB@ @MATHLIB@
+	$(CC) -o $@ $^ $(CFLAGS) $(LIBS) @MATHLIB@
 
 testhaptic$(EXE): $(srcdir)/testhaptic.c
 	$(CC) -o $@ $^ $(CFLAGS) $(LIBS)
--- a/test/testgl2.c	Fri Dec 13 09:48:12 2013 -0300
+++ b/test/testgl2.c	Sat Dec 14 20:18:43 2013 -0300
@@ -24,11 +24,48 @@
 
 #include "SDL_opengl.h"
 
+typedef struct GL_Context
+{
+#define SDL_PROC(ret,func,params) ret (APIENTRY *func) params;
+#include "../src/render/opengl/SDL_glfuncs.h"
+#undef SDL_PROC
+} GL_Context;
+
+
 /* Undefine this if you want a flat cube instead of a rainbow cube */
 #define SHADED_CUBE
 
 static SDLTest_CommonState *state;
 static SDL_GLContext context;
+static GL_Context ctx;
+
+static int LoadContext(GL_Context * data)
+{
+#if SDL_VIDEO_DRIVER_UIKIT
+#define __SDL_NOGETPROCADDR__
+#elif SDL_VIDEO_DRIVER_ANDROID
+#define __SDL_NOGETPROCADDR__
+#elif SDL_VIDEO_DRIVER_PANDORA
+#define __SDL_NOGETPROCADDR__
+#endif
+
+#if defined __SDL_NOGETPROCADDR__
+#define SDL_PROC(ret,func,params) data->func=func;
+#else
+#define SDL_PROC(ret,func,params) \
+    do { \
+        data->func = SDL_GL_GetProcAddress(#func); \
+        if ( ! data->func ) { \
+            return SDL_SetError("Couldn't load GL function %s: %s\n", #func, SDL_GetError()); \
+        } \
+    } while ( 0 );
+#endif /* _SDL_NOGETPROCADDR_ */
+
+#include "../src/render/opengl/SDL_glfuncs.h"
+#undef SDL_PROC
+    return 0;
+}
+
 
 /* Call this instead of exit(), so we can clean up SDL: atexit() is evil. */
 static void
@@ -67,107 +104,107 @@
     };
 
     /* Do our drawing, too. */
-    glClearColor(0.0, 0.0, 0.0, 1.0);
-    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+    ctx.glClearColor(0.0, 0.0, 0.0, 1.0);
+    ctx.glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
-    glBegin(GL_QUADS);
+    ctx.glBegin(GL_QUADS);
 
 #ifdef SHADED_CUBE
-    glColor3fv(color[0]);
-    glVertex3fv(cube[0]);
-    glColor3fv(color[1]);
-    glVertex3fv(cube[1]);
-    glColor3fv(color[2]);
-    glVertex3fv(cube[2]);
-    glColor3fv(color[3]);
-    glVertex3fv(cube[3]);
+    ctx.glColor3fv(color[0]);
+    ctx.glVertex3fv(cube[0]);
+    ctx.glColor3fv(color[1]);
+    ctx.glVertex3fv(cube[1]);
+    ctx.glColor3fv(color[2]);
+    ctx.glVertex3fv(cube[2]);
+    ctx.glColor3fv(color[3]);
+    ctx.glVertex3fv(cube[3]);
 
-    glColor3fv(color[3]);
-    glVertex3fv(cube[3]);
-    glColor3fv(color[4]);
-    glVertex3fv(cube[4]);
-    glColor3fv(color[7]);
-    glVertex3fv(cube[7]);
-    glColor3fv(color[2]);
-    glVertex3fv(cube[2]);
+    ctx.glColor3fv(color[3]);
+    ctx.glVertex3fv(cube[3]);
+    ctx.glColor3fv(color[4]);
+    ctx.glVertex3fv(cube[4]);
+    ctx.glColor3fv(color[7]);
+    ctx.glVertex3fv(cube[7]);
+    ctx.glColor3fv(color[2]);
+    ctx.glVertex3fv(cube[2]);
 
-    glColor3fv(color[0]);
-    glVertex3fv(cube[0]);
-    glColor3fv(color[5]);
-    glVertex3fv(cube[5]);
-    glColor3fv(color[6]);
-    glVertex3fv(cube[6]);
-    glColor3fv(color[1]);
-    glVertex3fv(cube[1]);
+    ctx.glColor3fv(color[0]);
+    ctx.glVertex3fv(cube[0]);
+    ctx.glColor3fv(color[5]);
+    ctx.glVertex3fv(cube[5]);
+    ctx.glColor3fv(color[6]);
+    ctx.glVertex3fv(cube[6]);
+    ctx.glColor3fv(color[1]);
+    ctx.glVertex3fv(cube[1]);
 
-    glColor3fv(color[5]);
-    glVertex3fv(cube[5]);
-    glColor3fv(color[4]);
-    glVertex3fv(cube[4]);
-    glColor3fv(color[7]);
-    glVertex3fv(cube[7]);
-    glColor3fv(color[6]);
-    glVertex3fv(cube[6]);
+    ctx.glColor3fv(color[5]);
+    ctx.glVertex3fv(cube[5]);
+    ctx.glColor3fv(color[4]);
+    ctx.glVertex3fv(cube[4]);
+    ctx.glColor3fv(color[7]);
+    ctx.glVertex3fv(cube[7]);
+    ctx.glColor3fv(color[6]);
+    ctx.glVertex3fv(cube[6]);
 
-    glColor3fv(color[5]);
-    glVertex3fv(cube[5]);
-    glColor3fv(color[0]);
-    glVertex3fv(cube[0]);
-    glColor3fv(color[3]);
-    glVertex3fv(cube[3]);
-    glColor3fv(color[4]);
-    glVertex3fv(cube[4]);
+    ctx.glColor3fv(color[5]);
+    ctx.glVertex3fv(cube[5]);
+    ctx.glColor3fv(color[0]);
+    ctx.glVertex3fv(cube[0]);
+    ctx.glColor3fv(color[3]);
+    ctx.glVertex3fv(cube[3]);
+    ctx.glColor3fv(color[4]);
+    ctx.glVertex3fv(cube[4]);
 
-    glColor3fv(color[6]);
-    glVertex3fv(cube[6]);
-    glColor3fv(color[1]);
-    glVertex3fv(cube[1]);
-    glColor3fv(color[2]);
-    glVertex3fv(cube[2]);
-    glColor3fv(color[7]);
-    glVertex3fv(cube[7]);
+    ctx.glColor3fv(color[6]);
+    ctx.glVertex3fv(cube[6]);
+    ctx.glColor3fv(color[1]);
+    ctx.glVertex3fv(cube[1]);
+    ctx.glColor3fv(color[2]);
+    ctx.glVertex3fv(cube[2]);
+    ctx.glColor3fv(color[7]);
+    ctx.glVertex3fv(cube[7]);
 #else /* flat cube */
-    glColor3f(1.0, 0.0, 0.0);
-    glVertex3fv(cube[0]);
-    glVertex3fv(cube[1]);
-    glVertex3fv(cube[2]);
-    glVertex3fv(cube[3]);
+    ctx.glColor3f(1.0, 0.0, 0.0);
+    ctx.glVertex3fv(cube[0]);
+    ctx.glVertex3fv(cube[1]);
+    ctx.glVertex3fv(cube[2]);
+    ctx.glVertex3fv(cube[3]);
 
-    glColor3f(0.0, 1.0, 0.0);
-    glVertex3fv(cube[3]);
-    glVertex3fv(cube[4]);
-    glVertex3fv(cube[7]);
-    glVertex3fv(cube[2]);
+    ctx.glColor3f(0.0, 1.0, 0.0);
+    ctx.glVertex3fv(cube[3]);
+    ctx.glVertex3fv(cube[4]);
+    ctx.glVertex3fv(cube[7]);
+    ctx.glVertex3fv(cube[2]);
 
-    glColor3f(0.0, 0.0, 1.0);
-    glVertex3fv(cube[0]);
-    glVertex3fv(cube[5]);
-    glVertex3fv(cube[6]);
-    glVertex3fv(cube[1]);
+    ctx.glColor3f(0.0, 0.0, 1.0);
+    ctx.glVertex3fv(cube[0]);
+    ctx.glVertex3fv(cube[5]);
+    ctx.glVertex3fv(cube[6]);
+    ctx.glVertex3fv(cube[1]);
 
-    glColor3f(0.0, 1.0, 1.0);
-    glVertex3fv(cube[5]);
-    glVertex3fv(cube[4]);
-    glVertex3fv(cube[7]);
-    glVertex3fv(cube[6]);
+    ctx.glColor3f(0.0, 1.0, 1.0);
+    ctx.glVertex3fv(cube[5]);
+    ctx.glVertex3fv(cube[4]);
+    ctx.glVertex3fv(cube[7]);
+    ctx.glVertex3fv(cube[6]);
 
-    glColor3f(1.0, 1.0, 0.0);
-    glVertex3fv(cube[5]);
-    glVertex3fv(cube[0]);
-    glVertex3fv(cube[3]);
-    glVertex3fv(cube[4]);
+    ctx.glColor3f(1.0, 1.0, 0.0);
+    ctx.glVertex3fv(cube[5]);
+    ctx.glVertex3fv(cube[0]);
+    ctx.glVertex3fv(cube[3]);
+    ctx.glVertex3fv(cube[4]);
 
-    glColor3f(1.0, 0.0, 1.0);
-    glVertex3fv(cube[6]);
-    glVertex3fv(cube[1]);
-    glVertex3fv(cube[2]);
-    glVertex3fv(cube[7]);
+    ctx.glColor3f(1.0, 0.0, 1.0);
+    ctx.glVertex3fv(cube[6]);
+    ctx.glVertex3fv(cube[1]);
+    ctx.glVertex3fv(cube[2]);
+    ctx.glVertex3fv(cube[7]);
 #endif /* SHADED_CUBE */
 
-    glEnd();
+    ctx.glEnd();
 
-    glMatrixMode(GL_MODELVIEW);
-    glRotatef(5.0, 1.0, 1.0, 1.0);
+    ctx.glMatrixMode(GL_MODELVIEW);
+    ctx.glRotatef(5.0, 1.0, 1.0, 1.0);
 }
 
 int
@@ -242,6 +279,13 @@
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_GL_CreateContext(): %s\n", SDL_GetError());
         quit(2);
     }
+    
+    /* Important: call this *after* creating the context */
+    if (LoadContext(&ctx) < 0) {
+        SDL_Log("Could not load GL functions\n");
+        quit(2);
+        return 0;
+    }
 
     if (state->render_flags & SDL_RENDERER_PRESENTVSYNC) {
         /* try late-swap-tearing first. If not supported, try normal vsync. */
@@ -260,10 +304,10 @@
     SDL_GL_GetDrawableSize(state->windows[0], &dw, &dh);
     SDL_Log("Draw Size     : %d,%d\n", dw, dh);
     SDL_Log("\n");
-    SDL_Log("Vendor        : %s\n", glGetString(GL_VENDOR));
-    SDL_Log("Renderer      : %s\n", glGetString(GL_RENDERER));
-    SDL_Log("Version       : %s\n", glGetString(GL_VERSION));
-    SDL_Log("Extensions    : %s\n", glGetString(GL_EXTENSIONS));
+    SDL_Log("Vendor        : %s\n", ctx.glGetString(GL_VENDOR));
+    SDL_Log("Renderer      : %s\n", ctx.glGetString(GL_RENDERER));
+    SDL_Log("Version       : %s\n", ctx.glGetString(GL_VERSION));
+    SDL_Log("Extensions    : %s\n", ctx.glGetString(GL_EXTENSIONS));
     SDL_Log("\n");
 
     status = SDL_GL_GetAttribute(SDL_GL_RED_SIZE, &value);
@@ -319,14 +363,14 @@
     }
 
     /* Set rendering settings */
-    glMatrixMode(GL_PROJECTION);
-    glLoadIdentity();
-    glOrtho(-2.0, 2.0, -2.0, 2.0, -20.0, 20.0);
-    glMatrixMode(GL_MODELVIEW);
-    glLoadIdentity();
-    glEnable(GL_DEPTH_TEST);
-    glDepthFunc(GL_LESS);
-    glShadeModel(GL_SMOOTH);
+    ctx.glMatrixMode(GL_PROJECTION);
+    ctx.glLoadIdentity();
+    ctx.glOrtho(-2.0, 2.0, -2.0, 2.0, -20.0, 20.0);
+    ctx.glMatrixMode(GL_MODELVIEW);
+    ctx.glLoadIdentity();
+    ctx.glEnable(GL_DEPTH_TEST);
+    ctx.glDepthFunc(GL_LESS);
+    ctx.glShadeModel(GL_SMOOTH);
     
     /* Main render loop */
     frames = 0;
@@ -344,7 +388,7 @@
                 continue;
             SDL_GL_MakeCurrent(state->windows[i], context);
             SDL_GL_GetDrawableSize(state->windows[i], &w, &h);
-            glViewport(0, 0, w, h);
+            ctx.glViewport(0, 0, w, h);
             Render();
             SDL_GL_SwapWindow(state->windows[i]);
         }