Introduce experimental Wayland backend

This patch introduces a new backend that enables GLFW applications to
run on Wayland. For now, only output is supported (windowed and
fullscreen). Pointer cursor management, input devices, clipboard etc are
not supported yet.

There are some concepts that can not be supported, more specifically
glfwSetWindowPos, glfwGetWindowPos and glfwSetCursorPos, as they are not
supported by Wayland.

This patch also changes the time and joystick implementations used by the
X11 backend to be shared between the Wayland backend and the X11 backend.
This commit is contained in:
Jonas Ådahl 2014-03-17 22:53:43 +01:00 committed by Camilla Berglund
parent 99c98407c9
commit 8e99996321
16 changed files with 1242 additions and 57 deletions

View File

@ -0,0 +1,62 @@
# Try to find Wayland on a Unix system
#
# This will define:
#
# WAYLAND_FOUND - True if Wayland is found
# WAYLAND_LIBRARIES - Link these to use Wayland
# WAYLAND_INCLUDE_DIR - Include directory for Wayland
# WAYLAND_DEFINITIONS - Compiler flags for using Wayland
#
# In addition the following more fine grained variables will be defined:
#
# WAYLAND_CLIENT_FOUND WAYLAND_CLIENT_INCLUDE_DIR WAYLAND_CLIENT_LIBRARIES
# WAYLAND_SERVER_FOUND WAYLAND_SERVER_INCLUDE_DIR WAYLAND_SERVER_LIBRARIES
# WAYLAND_EGL_FOUND WAYLAND_EGL_INCLUDE_DIR WAYLAND_EGL_LIBRARIES
#
# Copyright (c) 2013 Martin Gräßlin <mgraesslin@kde.org>
#
# Redistribution and use is allowed according to the terms of the BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
IF (NOT WIN32)
IF (WAYLAND_INCLUDE_DIR AND WAYLAND_LIBRARIES)
# In the cache already
SET(WAYLAND_FIND_QUIETLY TRUE)
ENDIF ()
# Use pkg-config to get the directories and then use these values
# in the FIND_PATH() and FIND_LIBRARY() calls
FIND_PACKAGE(PkgConfig)
PKG_CHECK_MODULES(PKG_WAYLAND QUIET wayland-client wayland-server wayland-egl)
SET(WAYLAND_DEFINITIONS ${PKG_WAYLAND_CFLAGS})
FIND_PATH(WAYLAND_CLIENT_INCLUDE_DIR NAMES wayland-client.h HINTS ${PKG_WAYLAND_INCLUDE_DIRS})
FIND_PATH(WAYLAND_SERVER_INCLUDE_DIR NAMES wayland-server.h HINTS ${PKG_WAYLAND_INCLUDE_DIRS})
FIND_PATH(WAYLAND_EGL_INCLUDE_DIR NAMES wayland-egl.h HINTS ${PKG_WAYLAND_INCLUDE_DIRS})
FIND_LIBRARY(WAYLAND_CLIENT_LIBRARIES NAMES wayland-client HINTS ${PKG_WAYLAND_LIBRARY_DIRS})
FIND_LIBRARY(WAYLAND_SERVER_LIBRARIES NAMES wayland-server HINTS ${PKG_WAYLAND_LIBRARY_DIRS})
FIND_LIBRARY(WAYLAND_EGL_LIBRARIES NAMES wayland-egl HINTS ${PKG_WAYLAND_LIBRARY_DIRS})
set(WAYLAND_INCLUDE_DIR ${WAYLAND_CLIENT_INCLUDE_DIR} ${WAYLAND_SERVER_INCLUDE_DIR} ${WAYLAND_EGL_INCLUDE_DIR})
set(WAYLAND_LIBRARIES ${WAYLAND_CLIENT_LIBRARIES} ${WAYLAND_SERVER_LIBRARIES} ${WAYLAND_EGL_LIBRARIES})
list(REMOVE_DUPLICATES WAYLAND_INCLUDE_DIR)
include(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(WAYLAND_CLIENT DEFAULT_MSG WAYLAND_CLIENT_LIBRARIES WAYLAND_CLIENT_INCLUDE_DIR)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(WAYLAND_SERVER DEFAULT_MSG WAYLAND_SERVER_LIBRARIES WAYLAND_SERVER_INCLUDE_DIR)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(WAYLAND_EGL DEFAULT_MSG WAYLAND_EGL_LIBRARIES WAYLAND_EGL_INCLUDE_DIR)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(WAYLAND DEFAULT_MSG WAYLAND_LIBRARIES WAYLAND_INCLUDE_DIR)
MARK_AS_ADVANCED(
WAYLAND_INCLUDE_DIR WAYLAND_LIBRARIES
WAYLAND_CLIENT_INCLUDE_DIR WAYLAND_CLIENT_LIBRARIES
WAYLAND_SERVER_INCLUDE_DIR WAYLAND_SERVER_LIBRARIES
WAYLAND_EGL_INCLUDE_DIR WAYLAND_EGL_LIBRARIES
)
ENDIF ()

View File

@ -31,6 +31,10 @@ else()
option(GLFW_USE_EGL "Use EGL for context creation" OFF)
endif()
if (UNIX)
option(GLFW_USE_WAYLAND "Use Wayland for context creation (implies EGL as well)" OFF)
endif()
if (MSVC)
option(USE_MSVC_RUNTIME_LIBRARY_DLL "Use MSVC runtime library DLL" ON)
endif()
@ -39,6 +43,10 @@ if (BUILD_SHARED_LIBS)
set(_GLFW_BUILD_DLL 1)
endif()
if (GLFW_USE_WAYLAND)
set(GLFW_USE_EGL 1)
endif()
if (GLFW_USE_EGL)
set(GLFW_CLIENT_LIBRARY "opengl" CACHE STRING
"The client library to use; one of opengl, glesv1 or glesv2")
@ -136,8 +144,13 @@ elseif (APPLE)
set(_GLFW_NSGL 1)
message(STATUS "Using NSGL for context creation")
elseif (UNIX)
set(_GLFW_X11 1)
message(STATUS "Using X11 for window creation")
if (GLFW_USE_WAYLAND)
set(_GLFW_WAYLAND 1)
message(STATUS "Using Wayland for window creation")
else()
set(_GLFW_X11 1)
message(STATUS "Using X11 for window creation")
endif()
if (GLFW_USE_EGL)
set(_GLFW_EGL 1)
@ -189,7 +202,6 @@ if (_GLFW_WGL)
list(APPEND glfw_INCLUDE_DIRS ${OPENGL_INCLUDE_DIR})
list(APPEND glfw_LIBRARIES ${OPENGL_gl_LIBRARY})
endif()
#--------------------------------------------------------------------
@ -279,6 +291,24 @@ if (_GLFW_X11)
endif()
#--------------------------------------------------------------------
# Use Wayland for window creation
#--------------------------------------------------------------------
if (_GLFW_WAYLAND)
find_package(Wayland REQUIRED)
set(GLFW_PKG_DEPS "${GLFW_PKG_DEPS} wayland")
list(APPEND glfw_INCLUDE_DIRS ${WAYLAND_INCLUDE_DIR})
list(APPEND glfw_LIBRARIES ${WAYLAND_LIBRARIES})
find_library(MATH_LIBRARY m)
mark_as_advanced(MATH_LIBRARY)
if (MATH_LIBRARY)
list(APPEND glfw_LIBRARIES ${MATH_LIBRARY})
set(GLFW_PKG_LIBS "${GLFW_PKG_LIBS} -lm")
endif()
endif()
#--------------------------------------------------------------------
# Use GLX for context creation
#--------------------------------------------------------------------

View File

@ -22,10 +22,19 @@ elseif (_GLFW_WIN32)
win32_init.c win32_joystick.c win32_monitor.c win32_time.c
win32_tls.c win32_window.c)
elseif (_GLFW_X11)
set(glfw_HEADERS ${common_HEADERS} x11_platform.h posix_tls.h)
set(glfw_HEADERS ${common_HEADERS} x11_platform.h posix_tls.h unix_time.h)
set(glfw_SOURCES ${common_SOURCES} x11_clipboard.c x11_gamma.c x11_init.c
x11_joystick.c x11_monitor.c x11_time.c x11_window.c
x11_unicode.c posix_tls.c)
x11_monitor.c x11_window.c x11_unicode.c posix_tls.c)
elseif (_GLFW_WAYLAND)
set(glfw_HEADERS ${common_HEADERS} wayland_platform.h posix_tls.h)
set(glfw_SOURCES ${common_SOURCES} wayland_clipboard.c wayland_gamma.c
wayland_init.c wayland_monitor.c wayland_window.c
posix_tls.c)
endif()
if (_GLFW_X11 OR _GLFW_WAYLAND)
list(APPEND glfw_HEADERS linux_joystick.h unix_time.h)
list(APPEND glfw_SOURCES linux_joystick.c unix_time.c)
endif()
if (_GLFW_EGL)

View File

@ -40,6 +40,8 @@
#cmakedefine _GLFW_WIN32
// Define this to 1 if building GLFW for Cocoa
#cmakedefine _GLFW_COCOA
// Define this to 1 if building GLFW for Wayland
#cmakedefine _GLFW_WAYLAND
// Define this to 1 if building GLFW for EGL
#cmakedefine _GLFW_EGL

View File

@ -72,6 +72,8 @@ typedef struct _GLFWcursor _GLFWcursor;
#include "win32_platform.h"
#elif defined(_GLFW_X11)
#include "x11_platform.h"
#elif defined(_GLFW_WAYLAND)
#include "wayland_platform.h"
#else
#error "No supported window creation API selected"
#endif

View File

@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.1 X11 - www.glfw.org
// GLFW 3.1 Linux - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2010 Camilla Berglund <elmindreda@elmindreda.org>
@ -39,6 +39,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#endif // __linux__
@ -55,7 +56,7 @@ static int openJoystickDevice(int joy, const char* path)
if (fd == -1)
return GL_FALSE;
_glfw.x11.joystick[joy].fd = fd;
_GLFW_LINUX_JOYSTICK_CONTEXT.joystick[joy].fd = fd;
// Verify that the joystick driver version is at least 1.0
ioctl(fd, JSIOCGVERSION, &version);
@ -69,18 +70,20 @@ static int openJoystickDevice(int joy, const char* path)
if (ioctl(fd, JSIOCGNAME(sizeof(name)), name) < 0)
strncpy(name, "Unknown", sizeof(name));
_glfw.x11.joystick[joy].name = strdup(name);
_GLFW_LINUX_JOYSTICK_CONTEXT.joystick[joy].name = strdup(name);
ioctl(fd, JSIOCGAXES, &axisCount);
_glfw.x11.joystick[joy].axisCount = (int) axisCount;
_GLFW_LINUX_JOYSTICK_CONTEXT.joystick[joy].axisCount = (int) axisCount;
ioctl(fd, JSIOCGBUTTONS, &buttonCount);
_glfw.x11.joystick[joy].buttonCount = (int) buttonCount;
_GLFW_LINUX_JOYSTICK_CONTEXT.joystick[joy].buttonCount = (int) buttonCount;
_glfw.x11.joystick[joy].axes = calloc(axisCount, sizeof(float));
_glfw.x11.joystick[joy].buttons = calloc(buttonCount, 1);
_GLFW_LINUX_JOYSTICK_CONTEXT.joystick[joy].axes =
calloc(axisCount, sizeof(float));
_GLFW_LINUX_JOYSTICK_CONTEXT.joystick[joy].buttons =
calloc(buttonCount, 1);
_glfw.x11.joystick[joy].present = GL_TRUE;
_GLFW_LINUX_JOYSTICK_CONTEXT.joystick[joy].present = GL_TRUE;
#endif // __linux__
return GL_TRUE;
@ -97,21 +100,23 @@ static void pollJoystickEvents(void)
for (i = 0; i <= GLFW_JOYSTICK_LAST; i++)
{
if (!_glfw.x11.joystick[i].present)
if (!_GLFW_LINUX_JOYSTICK_CONTEXT.joystick[i].present)
continue;
// Read all queued events (non-blocking)
for (;;)
{
errno = 0;
result = read(_glfw.x11.joystick[i].fd, &e, sizeof(e));
result = read(_GLFW_LINUX_JOYSTICK_CONTEXT.joystick[i].fd,
&e,
sizeof(e));
if (errno == ENODEV)
{
free(_glfw.x11.joystick[i].axes);
free(_glfw.x11.joystick[i].buttons);
free(_glfw.x11.joystick[i].name);
_glfw.x11.joystick[i].present = GL_FALSE;
free(_GLFW_LINUX_JOYSTICK_CONTEXT.joystick[i].axes);
free(_GLFW_LINUX_JOYSTICK_CONTEXT.joystick[i].buttons);
free(_GLFW_LINUX_JOYSTICK_CONTEXT.joystick[i].name);
_GLFW_LINUX_JOYSTICK_CONTEXT.joystick[i].present = GL_FALSE;
}
if (result == -1)
@ -123,12 +128,12 @@ static void pollJoystickEvents(void)
switch (e.type)
{
case JS_EVENT_AXIS:
_glfw.x11.joystick[i].axes[e.number] =
_GLFW_LINUX_JOYSTICK_CONTEXT.joystick[i].axes[e.number] =
(float) e.value / 32767.0f;
break;
case JS_EVENT_BUTTON:
_glfw.x11.joystick[i].buttons[e.number] =
_GLFW_LINUX_JOYSTICK_CONTEXT.joystick[i].buttons[e.number] =
e.value ? GLFW_PRESS : GLFW_RELEASE;
break;
@ -203,14 +208,14 @@ void _glfwTerminateJoysticks(void)
for (i = 0; i <= GLFW_JOYSTICK_LAST; i++)
{
if (_glfw.x11.joystick[i].present)
if (_GLFW_LINUX_JOYSTICK_CONTEXT.joystick[i].present)
{
close(_glfw.x11.joystick[i].fd);
free(_glfw.x11.joystick[i].axes);
free(_glfw.x11.joystick[i].buttons);
free(_glfw.x11.joystick[i].name);
close(_GLFW_LINUX_JOYSTICK_CONTEXT.joystick[i].fd);
free(_GLFW_LINUX_JOYSTICK_CONTEXT.joystick[i].axes);
free(_GLFW_LINUX_JOYSTICK_CONTEXT.joystick[i].buttons);
free(_GLFW_LINUX_JOYSTICK_CONTEXT.joystick[i].name);
_glfw.x11.joystick[i].present = GL_FALSE;
_GLFW_LINUX_JOYSTICK_CONTEXT.joystick[i].present = GL_FALSE;
}
}
#endif // __linux__
@ -225,35 +230,35 @@ int _glfwPlatformJoystickPresent(int joy)
{
pollJoystickEvents();
return _glfw.x11.joystick[joy].present;
return _GLFW_LINUX_JOYSTICK_CONTEXT.joystick[joy].present;
}
const float* _glfwPlatformGetJoystickAxes(int joy, int* count)
{
pollJoystickEvents();
if (!_glfw.x11.joystick[joy].present)
if (!_GLFW_LINUX_JOYSTICK_CONTEXT.joystick[joy].present)
return NULL;
*count = _glfw.x11.joystick[joy].axisCount;
return _glfw.x11.joystick[joy].axes;
*count = _GLFW_LINUX_JOYSTICK_CONTEXT.joystick[joy].axisCount;
return _GLFW_LINUX_JOYSTICK_CONTEXT.joystick[joy].axes;
}
const unsigned char* _glfwPlatformGetJoystickButtons(int joy, int* count)
{
pollJoystickEvents();
if (!_glfw.x11.joystick[joy].present)
if (!_GLFW_LINUX_JOYSTICK_CONTEXT.joystick[joy].present)
return NULL;
*count = _glfw.x11.joystick[joy].buttonCount;
return _glfw.x11.joystick[joy].buttons;
*count = _GLFW_LINUX_JOYSTICK_CONTEXT.joystick[joy].buttonCount;
return _GLFW_LINUX_JOYSTICK_CONTEXT.joystick[joy].buttons;
}
const char* _glfwPlatformGetJoystickName(int joy)
{
pollJoystickEvents();
return _glfw.x11.joystick[joy].name;
return _GLFW_LINUX_JOYSTICK_CONTEXT.joystick[joy].name;
}

46
src/linux_joystick.h Normal file
View File

@ -0,0 +1,46 @@
//========================================================================
// GLFW 3.1 Linux - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2014 Jonas Ådahl <jadahl@gmail.com>
//
// 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 _linux_joystick_h_
#define _linux_joystick_h_
typedef struct _GLFWjoystickLinux {
struct {
int present;
int fd;
float* axes;
int axisCount;
unsigned char* buttons;
int buttonCount;
char* name;
} joystick[GLFW_JOYSTICK_LAST + 1];
} _GLFWjoystickLinux;
// Joystick input
void _glfwInitJoysticks(void);
void _glfwTerminateJoysticks(void);
#endif // _linux_joystick_h_

96
src/unix_time.c Normal file
View File

@ -0,0 +1,96 @@
//========================================================================
// GLFW 3.1 UNIX - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2010 Camilla Berglund <elmindreda@elmindreda.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 "internal.h"
#include <sys/time.h>
#include <time.h>
// Return raw time
//
static uint64_t getRawTime(void)
{
#if defined(CLOCK_MONOTONIC)
if (_GLFW_UNIX_TIME_CONTEXT.monotonic)
{
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return (uint64_t) ts.tv_sec * (uint64_t) 1000000000 + (uint64_t) ts.tv_nsec;
}
else
#endif
{
struct timeval tv;
gettimeofday(&tv, NULL);
return (uint64_t) tv.tv_sec * (uint64_t) 1000000 + (uint64_t) tv.tv_usec;
}
}
//////////////////////////////////////////////////////////////////////////
////// GLFW internal API //////
//////////////////////////////////////////////////////////////////////////
// Initialise timer
//
void _glfwInitTimer(void)
{
#if defined(CLOCK_MONOTONIC)
struct timespec ts;
if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0)
{
_GLFW_UNIX_TIME_CONTEXT.monotonic = GL_TRUE;
_GLFW_UNIX_TIME_CONTEXT.resolution = 1e-9;
}
else
#endif
{
_GLFW_UNIX_TIME_CONTEXT.resolution = 1e-6;
}
_GLFW_UNIX_TIME_CONTEXT.base = getRawTime();
}
//////////////////////////////////////////////////////////////////////////
////// GLFW platform API //////
//////////////////////////////////////////////////////////////////////////
double _glfwPlatformGetTime(void)
{
return (double) (getRawTime() - _GLFW_UNIX_TIME_CONTEXT.base) *
_GLFW_UNIX_TIME_CONTEXT.resolution;
}
void _glfwPlatformSetTime(double time)
{
_GLFW_UNIX_TIME_CONTEXT.base = getRawTime() -
(uint64_t) (time / _GLFW_UNIX_TIME_CONTEXT.resolution);
}

42
src/unix_time.h Normal file
View File

@ -0,0 +1,42 @@
//========================================================================
// GLFW 3.1 UNIX - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2010 Camilla Berglund <elmindreda@elmindreda.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 _unix_time_h_
#define _unix_time_h_
#include <stdint.h>
#include <GL/gl.h>
typedef struct _GLFWtimeUNIX{
GLboolean monotonic;
double resolution;
uint64_t base;
} _GLFWtimeUNIX;
void _glfwInitTimer(void);
#endif // _unix_time_h_

47
src/wayland_clipboard.c Normal file
View File

@ -0,0 +1,47 @@
//========================================================================
// GLFW 3.1 Wayland - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2014 Jonas Ådahl <jadahl@gmail.com>
//
// 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 "internal.h"
#include <stdio.h>
//////////////////////////////////////////////////////////////////////////
////// GLFW platform API //////
//////////////////////////////////////////////////////////////////////////
void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string)
{
// TODO
fprintf(stderr, "_glfwPlatformSetClipboardString not implemented yet\n");
}
const char* _glfwPlatformGetClipboardString(_GLFWwindow* window)
{
// TODO
fprintf(stderr, "_glfwPlatformGetClipboardString not implemented yet\n");
return NULL;
}

46
src/wayland_gamma.c Normal file
View File

@ -0,0 +1,46 @@
//========================================================================
// GLFW 3.1 Wayland - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2014 Jonas Ådahl <jadahl@gmail.com>
//
// 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 "internal.h"
#include <stdio.h>
//////////////////////////////////////////////////////////////////////////
////// GLFW platform API //////
//////////////////////////////////////////////////////////////////////////
void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
{
// TODO
fprintf(stderr, "_glfwPlatformGetGammaRamp not implemented yet\n");
}
void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp)
{
// TODO
fprintf(stderr, "_glfwPlatformSetGammaRamp not implemented yet\n");
}

159
src/wayland_init.c Normal file
View File

@ -0,0 +1,159 @@
//========================================================================
// GLFW 3.1 Wayland - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2014 Jonas Ådahl <jadahl@gmail.com>
//
// 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 "internal.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wayland-client.h>
#include <wayland-client-protocol.h>
#include <wayland-cursor.h>
static void
handlePing(void* data,
struct wl_shell_surface* shellSurface,
uint32_t serial)
{
wl_shell_surface_pong(shellSurface, serial);
}
static void
handleConfigure(void* data,
struct wl_shell_surface* shellSurface,
uint32_t edges,
int32_t width,
int32_t height)
{
}
static void
handlePopupDone(void *data, struct wl_shell_surface *shell_surface)
{
}
static const struct wl_shell_surface_listener shellSurfaceListener = {
handlePing,
handleConfigure,
handlePopupDone
};
static void registryHandleGlobal(void* data,
struct wl_registry* registry,
uint32_t name,
const char* interface,
uint32_t version)
{
_GLFWlibraryWayland* wayland = &_glfw.wayland;
if (strcmp(interface, "wl_compositor") == 0)
{
wayland->compositor =
wl_registry_bind(registry, name, &wl_compositor_interface, 1);
}
else if (strcmp(interface, "wl_shell") == 0)
{
wayland->shell =
wl_registry_bind(registry, name, &wl_shell_interface, 1);
}
else if (strcmp(interface, "wl_output") == 0)
{
_glfwAddOutput(name, version);
}
}
static void registryHandleGlobalRemove(void *data,
struct wl_registry *registry,
uint32_t name)
{
}
static const struct wl_registry_listener registryListener = {
registryHandleGlobal,
registryHandleGlobalRemove
};
//////////////////////////////////////////////////////////////////////////
////// GLFW platform API //////
//////////////////////////////////////////////////////////////////////////
int _glfwPlatformInit(void)
{
_glfw.wayland.display = wl_display_connect(NULL);
if (!_glfw.wayland.display)
return GL_FALSE;
_glfw.wayland.registry = wl_display_get_registry(_glfw.wayland.display);
wl_registry_add_listener(_glfw.wayland.registry, &registryListener, NULL);
_glfw.wayland.monitors = calloc(4, sizeof(_GLFWmonitor*));
if (!_glfw.wayland.monitors)
return GL_FALSE;
_glfw.wayland.monitorsSize = 4;
// Sync so we got all registry objects.
wl_display_roundtrip(_glfw.wayland.display);
// Sync so we got all initial output events.
wl_display_roundtrip(_glfw.wayland.display);
if (!_glfwInitContextAPI())
return GL_FALSE;
_glfwInitTimer();
_glfwInitJoysticks();
return GL_TRUE;
}
void _glfwPlatformTerminate(void)
{
_glfwTerminateContextAPI();
if (_glfw.wayland.registry)
wl_registry_destroy(_glfw.wayland.registry);
if (_glfw.wayland.display)
wl_display_flush(_glfw.wayland.display);
if (_glfw.wayland.display)
wl_display_disconnect(_glfw.wayland.display);
}
const char* _glfwPlatformGetVersionString(void)
{
const char* version = _GLFW_VERSION_NUMBER " Wayland EGL "
#if defined(_POSIX_TIMERS) && defined(_POSIX_MONOTONIC_CLOCK)
" clock_gettime"
#endif
#if defined(_GLFW_BUILD_DLL)
" shared"
#endif
;
return version;
}

272
src/wayland_monitor.c Normal file
View File

@ -0,0 +1,272 @@
//========================================================================
// GLFW 3.1 Wayland - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2014 Jonas Ådahl <jadahl@gmail.com>
//
// 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 "internal.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
struct _GLFWvidmodeWayland {
GLFWvidmode base;
uint32_t flags;
};
static void geometry(void* data,
struct wl_output* output,
int32_t x,
int32_t y,
int32_t physicalWidth,
int32_t physicalHeight,
int32_t subpixel,
const char* make,
const char* model,
int32_t transform)
{
struct _GLFWmonitor *monitor = data;
monitor->wayland.x = x;
monitor->wayland.y = y;
monitor->widthMM = physicalWidth;
monitor->heightMM = physicalHeight;
}
static void mode(void* data,
struct wl_output* output,
uint32_t flags,
int32_t width,
int32_t height,
int32_t refresh)
{
struct _GLFWmonitor *monitor = data;
_GLFWvidmodeWayland mode = { { 0 }, };
mode.base.width = width;
mode.base.height = height;
mode.base.refreshRate = refresh;
mode.flags = flags;
if (monitor->wayland.modesCount + 1 >= monitor->wayland.modesSize)
{
int size = monitor->wayland.modesSize * 2;
_GLFWvidmodeWayland* modes =
realloc(monitor->wayland.modes,
monitor->wayland.modesSize * sizeof(_GLFWvidmodeWayland));
if (!modes)
{
return;
}
monitor->wayland.modes = modes;
monitor->wayland.modesSize = size;
}
monitor->wayland.modes[monitor->wayland.modesCount++] = mode;
}
static void done(void* data,
struct wl_output* output)
{
struct _GLFWmonitor *monitor = data;
monitor->wayland.done = GL_TRUE;
}
static void scale(void* data,
struct wl_output* output,
int32_t factor)
{
}
static const struct wl_output_listener output_listener = {
geometry,
mode,
done,
scale,
};
//////////////////////////////////////////////////////////////////////////
////// GLFW internal API //////
//////////////////////////////////////////////////////////////////////////
void _glfwAddOutput(uint32_t name, uint32_t version)
{
_GLFWmonitor *monitor;
struct wl_output *output;
char name_str[80];
memset(name_str, 0, 80 * sizeof(char));
snprintf(name_str, 79, "wl_output@%u", name);
if (version < 2)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Unsupported wl_output interface version");
return;
}
monitor = _glfwAllocMonitor(name_str, 0, 0);
output = wl_registry_bind(_glfw.wayland.registry,
name,
&wl_output_interface,
2);
if (!output)
{
_glfwFreeMonitor(monitor);
return;
}
monitor->wayland.modes = calloc(4, sizeof(_GLFWvidmodeWayland));
monitor->wayland.modesSize = 4;
monitor->wayland.output = output;
wl_output_add_listener(output, &output_listener, monitor);
if (_glfw.wayland.monitorsCount + 1 >= _glfw.wayland.monitorsSize)
{
_GLFWmonitor** monitors = _glfw.wayland.monitors;
int size = _glfw.wayland.monitorsSize * 2;
monitors = realloc(monitors, size * sizeof(_GLFWmonitor*));
if (!monitors)
{
wl_output_destroy(output);
_glfwFreeMonitor(monitor);
_glfwInputError(GLFW_PLATFORM_ERROR,
"Failed to retrieve monitor information");
return;
}
_glfw.wayland.monitors = monitors;
_glfw.wayland.monitorsSize = size;
}
_glfw.wayland.monitors[_glfw.wayland.monitorsCount++] = monitor;
}
//////////////////////////////////////////////////////////////////////////
////// GLFW platform API //////
//////////////////////////////////////////////////////////////////////////
_GLFWmonitor** _glfwPlatformGetMonitors(int* count)
{
_GLFWmonitor** monitors;
_GLFWmonitor* monitor;
int monitorsCount = _glfw.wayland.monitorsCount;
int i;
if (_glfw.wayland.monitorsCount == 0)
goto err;
monitors = calloc(monitorsCount, sizeof(_GLFWmonitor*));
if (!monitors)
goto err;
for (i = 0; i < monitorsCount; i++)
{
_GLFWmonitor* origMonitor = _glfw.wayland.monitors[i];
monitor = malloc(sizeof(_GLFWmonitor));
if (!monitor)
{
if (i > 0)
{
*count = i;
return monitors;
}
else
{
goto err_free;
}
}
monitor->modes =
_glfwPlatformGetVideoModes(origMonitor,
&origMonitor->wayland.modesCount);
*monitor = *_glfw.wayland.monitors[i];
monitors[i] = monitor;
}
*count = monitorsCount;
return monitors;
err_free:
free(monitors);
err:
*count = 0;
return NULL;
}
GLboolean _glfwPlatformIsSameMonitor(_GLFWmonitor* first, _GLFWmonitor* second)
{
return first->wayland.output == second->wayland.output;
}
void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos)
{
if (xpos)
*xpos = monitor->wayland.x;
if (ypos)
*ypos = monitor->wayland.y;
}
GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found)
{
GLFWvidmode *modes;
int modesCount = monitor->wayland.modesCount;
int i;
modes = calloc(modesCount, sizeof(GLFWvidmode));
if (!modes)
{
*found = 0;;
return NULL;
}
for (i = 0; i < modesCount; i++)
modes[i] = monitor->wayland.modes[i].base;
*found = modesCount;
return modes;
}
void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode)
{
int i;
for (i = 0; i < monitor->wayland.modesCount; i++)
{
if (monitor->wayland.modes[i].flags & WL_OUTPUT_MODE_CURRENT)
{
*mode = monitor->wayland.modes[i].base;
return;
}
}
}

99
src/wayland_platform.h Normal file
View File

@ -0,0 +1,99 @@
//========================================================================
// GLFW 3.1 Wayland - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2014 Jonas Ådahl <jadahl@gmail.com>
//
// 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 _wayland_platform_h_
#define _wayland_platform_h_
#if !defined(_GLFW_EGL)
#error "The Wayland backend depends on EGL platform support"
#endif
#include <wayland-client.h>
#include "egl_platform.h"
#include "linux_joystick.h"
#include "unix_time.h"
#define _GLFW_X11_CONTEXT_VISUAL window->egl.visual
#define _GLFW_EGL_NATIVE_WINDOW window->wayland.native
#define _GLFW_EGL_NATIVE_DISPLAY _glfw.wayland.display
#define _GLFW_UNIX_TIME_CONTEXT _glfw.wayland.timer
#define _GLFW_LINUX_JOYSTICK_CONTEXT _glfw.wayland.joystick
#define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowWayland wayland
#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryWayland wayland
#define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorWayland wayland
typedef struct _GLFWvidmodeWayland _GLFWvidmodeWayland;
typedef struct _GLFWwindowWayland
{
int width, height;
GLboolean visible;
struct wl_surface* surface;
struct wl_egl_window* native;
struct wl_shell_surface* shell_surface;
EGLSurface egl_surface;
struct wl_callback* callback;
} _GLFWwindowWayland;
typedef struct _GLFWlibraryWayland
{
struct wl_display* display;
struct wl_registry* registry;
struct wl_compositor* compositor;
struct wl_shell* shell;
_GLFWmonitor** monitors;
int monitorsCount;
int monitorsSize;
_GLFWtimeUNIX timer;
_GLFWjoystickLinux joystick;
} _GLFWlibraryWayland;
typedef struct _GLFWmonitorWayland
{
struct wl_output* output;
_GLFWvidmodeWayland* modes;
int modesCount;
int modesSize;
GLboolean done;
int x;
int y;
} _GLFWmonitorWayland;
//========================================================================
// Prototypes for platform specific internal functions
//========================================================================
void _glfwAddOutput(uint32_t name, uint32_t version);
#endif // _wayland_platform_h_

281
src/wayland_window.c Normal file
View File

@ -0,0 +1,281 @@
//========================================================================
// GLFW 3.1 Wayland - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2014 Jonas Ådahl <jadahl@gmail.com>
//
// 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 "internal.h"
#include <stdio.h>
#include <poll.h>
#include <GL/gl.h>
#include <wayland-egl.h>
static void
handlePing(void* data,
struct wl_shell_surface* shellSurface,
uint32_t serial)
{
wl_shell_surface_pong(shellSurface, serial);
}
static void
handleConfigure(void* data,
struct wl_shell_surface* shellSurface,
uint32_t edges,
int32_t width,
int32_t height)
{
}
static void
handlePopupDone(void* data,
struct wl_shell_surface* shellSurface)
{
}
static const struct wl_shell_surface_listener shellSurfaceListener = {
handlePing,
handleConfigure,
handlePopupDone
};
static GLboolean createSurface(_GLFWwindow* window,
const _GLFWwndconfig* wndconfig)
{
window->wayland.surface =
wl_compositor_create_surface(_glfw.wayland.compositor);
if (!window->wayland.surface)
return GL_FALSE;
window->wayland.native =
wl_egl_window_create(window->wayland.surface,
wndconfig->width,
wndconfig->height);
if (!window->wayland.native)
return GL_FALSE;
window->wayland.shell_surface =
wl_shell_get_shell_surface(_glfw.wayland.shell,
window->wayland.surface);
if (!window->wayland.shell_surface)
return GL_FALSE;
wl_shell_surface_add_listener(window->wayland.shell_surface,
&shellSurfaceListener,
window);
window->wayland.width = wndconfig->width;
window->wayland.height = wndconfig->height;
return GL_TRUE;
}
//////////////////////////////////////////////////////////////////////////
////// GLFW platform API //////
//////////////////////////////////////////////////////////////////////////
int _glfwPlatformCreateWindow(_GLFWwindow* window,
const _GLFWwndconfig* wndconfig,
const _GLFWctxconfig* ctxconfig,
const _GLFWfbconfig* fbconfig)
{
if (!_glfwCreateContext(window, ctxconfig, fbconfig))
return GL_FALSE;
if (!createSurface(window, wndconfig))
return GL_FALSE;
if (wndconfig->monitor)
{
wl_shell_surface_set_fullscreen(
window->wayland.shell_surface,
WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT,
0,
wndconfig->monitor->wayland.output);
}
else
{
wl_shell_surface_set_toplevel(window->wayland.shell_surface);
}
return GL_TRUE;
}
void _glfwPlatformDestroyWindow(_GLFWwindow* window)
{
if (window->wayland.native)
wl_egl_window_destroy(window->wayland.native);
_glfwDestroyContext(window);
if (window->wayland.shell_surface)
wl_shell_surface_destroy(window->wayland.shell_surface);
if (window->wayland.surface)
wl_surface_destroy(window->wayland.surface);
}
void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title)
{
wl_shell_surface_set_title(window->wayland.shell_surface, title);
}
void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos)
{
// A Wayland client is not aware of its position, so just warn and set it
// to (0, 0)
_glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland does not allow manual window positioning");
if (xpos)
*xpos = 0;
if (ypos)
*ypos = 0;
}
void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos)
{
// A Wayland client can not set its position, so just warn and set it
// to (0, 0)
_glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland does not allow manual window positioning");
}
void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height)
{
if (width)
*width = window->wayland.width;
if (height)
*height = window->wayland.height;
}
void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height)
{
wl_egl_window_resize(window->wayland.native, width, height, 0, 0);
window->wayland.width = width;
window->wayland.height = height;
}
void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height)
{
_glfwPlatformGetWindowSize(window, width, height);
}
void _glfwPlatformIconifyWindow(_GLFWwindow* window)
{
// TODO
fprintf(stderr, "_glfwPlatformIconifyWindow not implemented yet\n");
}
void _glfwPlatformRestoreWindow(_GLFWwindow* window)
{
// TODO
fprintf(stderr, "_glfwPlatformRestoreWindow not implemented yet\n");
}
void _glfwPlatformShowWindow(_GLFWwindow* window)
{
wl_shell_surface_set_toplevel(window->wayland.shell_surface);
}
void _glfwPlatformHideWindow(_GLFWwindow* window)
{
wl_surface_attach(window->wayland.surface, NULL, 0, 0);
wl_surface_commit(window->wayland.surface);
}
void _glfwPlatformPollEvents(void)
{
struct wl_display* display = _glfw.wayland.display;
struct pollfd fds[] = {
{ wl_display_get_fd(display), POLLIN },
};
while (wl_display_prepare_read(display) != 0)
wl_display_dispatch_pending(display);
wl_display_flush(display);
if (poll(fds, 1, 0) > 0)
{
wl_display_read_events(display);
wl_display_dispatch_pending(display);
}
else
{
wl_display_cancel_read(display);
}
}
void _glfwPlatformWaitEvents(void)
{
struct wl_display* display = _glfw.wayland.display;
struct pollfd fds[] = {
{ wl_display_get_fd(display), POLLIN },
};
while (wl_display_prepare_read(display) != 0)
wl_display_dispatch_pending(display);
wl_display_flush(display);
if (poll(fds, 1, -1) > 0)
{
wl_display_read_events(display);
wl_display_dispatch_pending(display);
}
else
{
wl_display_cancel_read(display);
}
}
void _glfwPlatformPostEmptyEvent(void)
{
wl_display_sync(_glfw.wayland.display);
}
void _glfwPlatformSetCursorPos(_GLFWwindow* window, double x, double y)
{
// A Wayland client can not set the cursor position.
_glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland does not allow cursor positioning");
}
void _glfwPlatformApplyCursorMode(_GLFWwindow* window)
{
fprintf(stderr, "_glfwPlatformApplyCursorMode not implemented yet\n");
switch (window->cursorMode)
{
case GLFW_CURSOR_NORMAL:
// TODO: enable showing cursor
break;
case GLFW_CURSOR_HIDDEN:
// TODO: enable not showing cursor
break;
case GLFW_CURSOR_DISABLED:
// TODO: enable pointer lock and hide cursor
break;
}
}

View File

@ -62,6 +62,12 @@
#error "No supported context creation API selected"
#endif
#define _GLFW_UNIX_TIME_CONTEXT _glfw.x11.timer
#include "unix_time.h"
#define _GLFW_LINUX_JOYSTICK_CONTEXT _glfw.x11.joystick
#include "linux_joystick.h"
#define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowX11 x11
#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryX11 x11
#define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorX11 x11
@ -199,11 +205,7 @@ typedef struct _GLFWlibraryX11
int exposure;
} saver;
struct {
GLboolean monotonic;
double resolution;
uint64_t base;
} timer;
_GLFWtimeUNIX timer;
struct {
char* string;
@ -213,15 +215,7 @@ typedef struct _GLFWlibraryX11
Window source;
} xdnd;
struct {
int present;
int fd;
float* axes;
int axisCount;
unsigned char* buttons;
int buttonCount;
char* name;
} joystick[GLFW_JOYSTICK_LAST + 1];
_GLFWjoystickLinux joystick;
} _GLFWlibraryX11;
@ -251,9 +245,6 @@ typedef struct _GLFWcursorX11
// Prototypes for platform specific internal functions
//========================================================================
// Time
void _glfwInitTimer(void);
// Gamma
void _glfwInitGammaRamp(void);
@ -261,10 +252,6 @@ void _glfwInitGammaRamp(void);
GLboolean _glfwSetVideoMode(_GLFWmonitor* monitor, const GLFWvidmode* desired);
void _glfwRestoreVideoMode(_GLFWmonitor* monitor);
// Joystick input
void _glfwInitJoysticks(void);
void _glfwTerminateJoysticks(void);
// Unicode support
long _glfwKeySym2Unicode(KeySym keysym);