From ec1cb49eab4d905698f2314d5e3e823af42ac96e Mon Sep 17 00:00:00 2001 From: Gabriel Jacobo Date: Sat, 14 Dec 2013 20:18:43 -0300 Subject: [PATCH] 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 | 2 + WhatsNew.txt | 7 +- cmake/sdlchecks.cmake | 23 ++ configure | 79 +++++ configure.in | 31 ++ include/SDL_config.h.cmake | 1 + include/SDL_config.h.in | 1 + include/SDL_syswm.h | 9 + src/render/opengl/SDL_glfuncs.h | 10 +- src/video/SDL_egl.c | 72 +++-- src/video/SDL_egl_c.h | 3 + src/video/SDL_sysvideo.h | 3 + src/video/SDL_video.c | 3 + src/video/wayland/SDL_waylandevents.c | 381 ++++++++++++++++++++++ src/video/wayland/SDL_waylandevents_c.h | 37 +++ src/video/wayland/SDL_waylandmouse.c | 407 ++++++++++++++++++++++++ src/video/wayland/SDL_waylandmouse.h | 31 ++ src/video/wayland/SDL_waylandopengles.c | 90 ++++++ src/video/wayland/SDL_waylandopengles.h | 46 +++ src/video/wayland/SDL_waylandvideo.c | 365 +++++++++++++++++++++ src/video/wayland/SDL_waylandvideo.h | 71 +++++ src/video/wayland/SDL_waylandwindow.c | 192 +++++++++++ src/video/wayland/SDL_waylandwindow.h | 58 ++++ test/Makefile.in | 4 +- test/testgl2.c | 238 ++++++++------ 25 files changed, 2035 insertions(+), 129 deletions(-) create mode 100644 src/video/wayland/SDL_waylandevents.c create mode 100644 src/video/wayland/SDL_waylandevents_c.h create mode 100644 src/video/wayland/SDL_waylandmouse.c create mode 100644 src/video/wayland/SDL_waylandmouse.h create mode 100644 src/video/wayland/SDL_waylandopengles.c create mode 100644 src/video/wayland/SDL_waylandopengles.h create mode 100644 src/video/wayland/SDL_waylandvideo.c create mode 100644 src/video/wayland/SDL_waylandvideo.h create mode 100644 src/video/wayland/SDL_waylandwindow.c create mode 100644 src/video/wayland/SDL_waylandwindow.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 7455ab84b..fb90299fc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -218,6 +218,7 @@ set_option(RPATH "Use an rpath when linking SDL" ${UNIX_SYS}) 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 @@ if(UNIX AND NOT APPLE) CheckDirectFB() CheckOpenGLX11() CheckOpenGLESX11() + CheckWayland() endif(SDL_VIDEO) if(LINUX) diff --git a/WhatsNew.txt b/WhatsNew.txt index e7cec5b60..db2ad8fb2 100644 --- a/WhatsNew.txt +++ b/WhatsNew.txt @@ -7,7 +7,10 @@ This is a list of major changes in SDL's version history. 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 @@ Android: Linux: * Fixed fullscreen and focused behavior when receiving NotifyGrab events - +* Wayland support --------------------------------------------------------------------------- 2.0.1: diff --git a/cmake/sdlchecks.cmake b/cmake/sdlchecks.cmake index 86366e493..c2286b87a 100644 --- a/cmake/sdlchecks.cmake +++ b/cmake/sdlchecks.cmake @@ -505,6 +505,29 @@ macro(CheckX11) endif(VIDEO_X11) 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 # diff --git a/configure b/configure index bd2c5d217..0cc698a10 100755 --- a/configure +++ b/configure @@ -817,6 +817,7 @@ enable_sndio enable_sndio_shared enable_diskaudio enable_dummyaudio +enable_video_wayland enable_video_x11 with_x enable_x11_shared @@ -1532,6 +1533,7 @@ Optional Features: --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 @@ $as_echo "$need_gcc_Wno_multichar" >&6; } 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 @@ case "$host" in CheckNAS CheckSNDIO CheckX11 + CheckWayland CheckDirectFB CheckFusionSound CheckOpenGLX11 diff --git a/configure.in b/configure.in index 7c3a1b1ce..941a255e6 100644 --- a/configure.in +++ b/configure.in @@ -1115,6 +1115,36 @@ CheckWarnAll() 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 @@ case "$host" in CheckNAS CheckSNDIO CheckX11 + CheckWayland CheckDirectFB CheckFusionSound CheckOpenGLX11 diff --git a/include/SDL_config.h.cmake b/include/SDL_config.h.cmake index 08237a87a..66a530b80 100644 --- a/include/SDL_config.h.cmake +++ b/include/SDL_config.h.cmake @@ -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@ diff --git a/include/SDL_config.h.in b/include/SDL_config.h.in index 536b29774..14ce7912c 100644 --- a/include/SDL_config.h.in +++ b/include/SDL_config.h.in @@ -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 diff --git a/include/SDL_syswm.h b/include/SDL_syswm.h index 5e4454f86..c43a78d28 100644 --- a/include/SDL_syswm.h +++ b/include/SDL_syswm.h @@ -101,6 +101,7 @@ typedef enum 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 @@ struct SDL_SysWMinfo 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 { diff --git a/src/render/opengl/SDL_glfuncs.h b/src/render/opengl/SDL_glfuncs.h index 7544929fc..c7e577b0e 100644 --- a/src/render/opengl/SDL_glfuncs.h +++ b/src/render/opengl/SDL_glfuncs.h @@ -30,7 +30,7 @@ SDL_PROC_UNUSED(void, glColor3bv, (const GLbyte *)) 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, glCopyTexSubImage2D, 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(void, glRectsv, (const GLshort * v1, const GLshort * v2)) 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, glVertex2sv, (const GLshort * v)) 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)) diff --git a/src/video/SDL_egl.c b/src/video/SDL_egl.c index c081a5da2..3ef24b038 100644 --- a/src/video/SDL_egl.c +++ b/src/video/SDL_egl.c @@ -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 @@ SDL_EGL_LoadLibrary(_THIS, const char *egl_path, NativeDisplayType native_displa } if (egl_dll_handle == NULL) { - 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; + 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); + } +#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 @@ SDL_EGL_LoadLibrary(_THIS, const char *egl_path, NativeDisplayType native_displa 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 @@ SDL_EGL_ChooseConfig(_THIS) } 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 @@ SDL_EGL_CreateContext(_THIS, EGLSurface egl_surface) 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"); diff --git a/src/video/SDL_egl_c.h b/src/video/SDL_egl_c.h index 3f0cd06ed..30d2b2de4 100644 --- a/src/video/SDL_egl_c.h +++ b/src/video/SDL_egl_c.h @@ -76,6 +76,9 @@ typedef struct SDL_EGL_VideoData EGLBoolean(EGLAPIENTRY *eglWaitNative) (EGLint engine); EGLBoolean(EGLAPIENTRY *eglWaitGL)(void); + + EGLBoolean(EGLAPIENTRY *eglBindAPI)(EGLenum); + } SDL_EGL_VideoData; /* OpenGLES functions */ diff --git a/src/video/SDL_sysvideo.h b/src/video/SDL_sysvideo.h index 18cf5f3c4..49f8363ad 100644 --- a/src/video/SDL_sysvideo.h +++ b/src/video/SDL_sysvideo.h @@ -369,6 +369,9 @@ extern VideoBootStrap RPI_bootstrap; #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); diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c index 77417297f..5aacac80f 100644 --- a/src/video/SDL_video.c +++ b/src/video/SDL_video.c @@ -85,6 +85,9 @@ static VideoBootStrap *bootstrap[] = { #endif #if SDL_VIDEO_DRIVER_DUMMY &DUMMY_bootstrap, +#endif +#if SDL_VIDEO_DRIVER_WAYLAND + &Wayland_bootstrap, #endif NULL }; diff --git a/src/video/wayland/SDL_waylandevents.c b/src/video/wayland/SDL_waylandevents.c new file mode 100644 index 000000000..b002a0500 --- /dev/null +++ b/src/video/wayland/SDL_waylandevents.c @@ -0,0 +1,381 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2013 Sam Lantinga + + 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 +#include +#include +#include +#include +#include +#include + +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: */ diff --git a/src/video/wayland/SDL_waylandevents_c.h b/src/video/wayland/SDL_waylandevents_c.h new file mode 100644 index 000000000..ed5ff7cc8 --- /dev/null +++ b/src/video/wayland/SDL_waylandevents_c.h @@ -0,0 +1,37 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2013 Sam Lantinga + + 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: */ diff --git a/src/video/wayland/SDL_waylandmouse.c b/src/video/wayland/SDL_waylandmouse.c new file mode 100644 index 000000000..62c65e94c --- /dev/null +++ b/src/video/wayland/SDL_waylandmouse.c @@ -0,0 +1,407 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2013 Sam Lantinga + + 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 +#include +#include +#include +#include +#include +#include + +#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 diff --git a/src/video/wayland/SDL_waylandmouse.h b/src/video/wayland/SDL_waylandmouse.h new file mode 100644 index 000000000..f434b9d82 --- /dev/null +++ b/src/video/wayland/SDL_waylandmouse.h @@ -0,0 +1,31 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2013 Sam Lantinga + + 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 diff --git a/src/video/wayland/SDL_waylandopengles.c b/src/video/wayland/SDL_waylandopengles.c new file mode 100644 index 000000000..7a1383981 --- /dev/null +++ b/src/video/wayland/SDL_waylandopengles.c @@ -0,0 +1,90 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2013 Sam Lantinga + + 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 diff --git a/src/video/wayland/SDL_waylandopengles.h b/src/video/wayland/SDL_waylandopengles.h new file mode 100644 index 000000000..2deed0c14 --- /dev/null +++ b/src/video/wayland/SDL_waylandopengles.h @@ -0,0 +1,46 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2013 Sam Lantinga + + 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 */ diff --git a/src/video/wayland/SDL_waylandvideo.c b/src/video/wayland/SDL_waylandvideo.c new file mode 100644 index 000000000..e75bea1dc --- /dev/null +++ b/src/video/wayland/SDL_waylandvideo.c @@ -0,0 +1,365 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2013 Sam Lantinga + + 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 +#include + +#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, ®istry_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: */ diff --git a/src/video/wayland/SDL_waylandvideo.h b/src/video/wayland/SDL_waylandvideo.h new file mode 100644 index 000000000..ca1b66f4e --- /dev/null +++ b/src/video/wayland/SDL_waylandvideo.h @@ -0,0 +1,71 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2013 Sam Lantinga + + 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 +#include +#include + +#include + +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: */ diff --git a/src/video/wayland/SDL_waylandwindow.c b/src/video/wayland/SDL_waylandwindow.c new file mode 100644 index 000000000..e530f5b80 --- /dev/null +++ b/src/video/wayland/SDL_waylandwindow.c @@ -0,0 +1,192 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2013 Sam Lantinga + + 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: */ diff --git a/src/video/wayland/SDL_waylandwindow.h b/src/video/wayland/SDL_waylandwindow.h new file mode 100644 index 000000000..f4f18361a --- /dev/null +++ b/src/video/wayland/SDL_waylandwindow.h @@ -0,0 +1,58 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2013 Sam Lantinga + + 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: */ diff --git a/test/Makefile.in b/test/Makefile.in index a534250fd..8a8c2b8f3 100644 --- a/test/Makefile.in +++ b/test/Makefile.in @@ -128,13 +128,13 @@ testgesture$(EXE): $(srcdir)/testgesture.c $(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) diff --git a/test/testgl2.c b/test/testgl2.c index 19685eae1..f51efe90d 100644 --- a/test/testgl2.c +++ b/test/testgl2.c @@ -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 @@ Render() }; /* 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 @@ main(int argc, char *argv[]) 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 @@ main(int argc, char *argv[]) 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 @@ main(int argc, char *argv[]) } /* 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 @@ main(int argc, char *argv[]) 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]); }