mirror of
https://github.com/glfw/glfw.git
synced 2024-11-10 00:51:47 +00:00
parent
8d170c7f47
commit
25204b1ec7
@ -27,21 +27,23 @@ IF (NOT WIN32)
|
||||
# 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)
|
||||
PKG_CHECK_MODULES(PKG_WAYLAND QUIET wayland-client wayland-server wayland-egl wayland-cursor)
|
||||
|
||||
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_PATH(WAYLAND_CURSOR_INCLUDE_DIR NAMES wayland-cursor.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})
|
||||
FIND_LIBRARY(WAYLAND_CURSOR_LIBRARIES NAMES wayland-cursor HINTS ${PKG_WAYLAND_LIBRARY_DIRS})
|
||||
|
||||
set(WAYLAND_INCLUDE_DIR ${WAYLAND_CLIENT_INCLUDE_DIR} ${WAYLAND_SERVER_INCLUDE_DIR} ${WAYLAND_EGL_INCLUDE_DIR})
|
||||
set(WAYLAND_INCLUDE_DIR ${WAYLAND_CLIENT_INCLUDE_DIR} ${WAYLAND_SERVER_INCLUDE_DIR} ${WAYLAND_EGL_INCLUDE_DIR} ${WAYLAND_CURSOR_INCLUDE_DIR})
|
||||
|
||||
set(WAYLAND_LIBRARIES ${WAYLAND_CLIENT_LIBRARIES} ${WAYLAND_SERVER_LIBRARIES} ${WAYLAND_EGL_LIBRARIES})
|
||||
set(WAYLAND_LIBRARIES ${WAYLAND_CLIENT_LIBRARIES} ${WAYLAND_SERVER_LIBRARIES} ${WAYLAND_EGL_LIBRARIES} ${WAYLAND_CURSOR_LIBRARIES})
|
||||
|
||||
list(REMOVE_DUPLICATES WAYLAND_INCLUDE_DIR)
|
||||
|
||||
@ -50,6 +52,7 @@ IF (NOT WIN32)
|
||||
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_EGL DEFAULT_MSG WAYLAND_CURSOR_LIBRARIES WAYLAND_CURSOR_INCLUDE_DIR)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(WAYLAND DEFAULT_MSG WAYLAND_LIBRARIES WAYLAND_INCLUDE_DIR)
|
||||
|
||||
MARK_AS_ADVANCED(
|
||||
@ -57,6 +60,7 @@ IF (NOT WIN32)
|
||||
WAYLAND_CLIENT_INCLUDE_DIR WAYLAND_CLIENT_LIBRARIES
|
||||
WAYLAND_SERVER_INCLUDE_DIR WAYLAND_SERVER_LIBRARIES
|
||||
WAYLAND_EGL_INCLUDE_DIR WAYLAND_EGL_LIBRARIES
|
||||
WAYLAND_CURSOR_INCLUDE_DIR WAYLAND_CURSOR_LIBRARIES
|
||||
)
|
||||
|
||||
ENDIF ()
|
||||
|
@ -46,7 +46,10 @@ static void pointerHandleEnter(void* data,
|
||||
{
|
||||
_GLFWwindow* window = wl_surface_get_user_data(surface);
|
||||
|
||||
_glfw.wl.pointerSerial = serial;
|
||||
_glfw.wl.pointerFocus = window;
|
||||
|
||||
_glfwPlatformSetCursor(window, window->wl.currentCursor);
|
||||
_glfwInputCursorEnter(window, GL_TRUE);
|
||||
}
|
||||
|
||||
@ -60,6 +63,7 @@ static void pointerHandleLeave(void* data,
|
||||
if (!window)
|
||||
return;
|
||||
|
||||
_glfw.wl.pointerSerial = serial;
|
||||
_glfw.wl.pointerFocus = NULL;
|
||||
_glfwInputCursorEnter(window, GL_FALSE);
|
||||
}
|
||||
@ -491,6 +495,11 @@ static void registryHandleGlobal(void* data,
|
||||
_glfw.wl.compositor =
|
||||
wl_registry_bind(registry, name, &wl_compositor_interface, 1);
|
||||
}
|
||||
else if (strcmp(interface, "wl_shm") == 0)
|
||||
{
|
||||
_glfw.wl.shm =
|
||||
wl_registry_bind(registry, name, &wl_shm_interface, 1);
|
||||
}
|
||||
else if (strcmp(interface, "wl_shell") == 0)
|
||||
{
|
||||
_glfw.wl.shell =
|
||||
@ -564,6 +573,20 @@ int _glfwPlatformInit(void)
|
||||
_glfwInitTimer();
|
||||
_glfwInitJoysticks();
|
||||
|
||||
if (_glfw.wl.pointer && _glfw.wl.shm){
|
||||
_glfw.wl.cursorTheme = wl_cursor_theme_load(NULL, 24, _glfw.wl.shm);
|
||||
if (!_glfw.wl.cursorTheme) {
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR, "Wayland: Unable to load default cursor theme\n");
|
||||
return GL_FALSE;
|
||||
}
|
||||
_glfw.wl.defaultCursor = wl_cursor_theme_get_cursor(_glfw.wl.cursorTheme, "left_ptr");
|
||||
if (!_glfw.wl.defaultCursor) {
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR, "Wayland: Unable to load default left pointer\n");
|
||||
return GL_FALSE;
|
||||
}
|
||||
_glfw.wl.cursorSurface = wl_compositor_create_surface(_glfw.wl.compositor);
|
||||
}
|
||||
|
||||
return GL_TRUE;
|
||||
}
|
||||
|
||||
@ -571,6 +594,10 @@ void _glfwPlatformTerminate(void)
|
||||
{
|
||||
_glfwTerminateContextAPI();
|
||||
|
||||
if (_glfw.wl.cursorTheme)
|
||||
wl_cursor_theme_destroy(_glfw.wl.cursorTheme);
|
||||
if (_glfw.wl.cursorSurface)
|
||||
wl_surface_destroy(_glfw.wl.cursorSurface);
|
||||
if (_glfw.wl.registry)
|
||||
wl_registry_destroy(_glfw.wl.registry);
|
||||
if (_glfw.wl.display)
|
||||
|
@ -66,7 +66,7 @@ typedef struct _GLFWwindowWayland
|
||||
struct wl_shell_surface* shell_surface;
|
||||
EGLSurface egl_surface;
|
||||
struct wl_callback* callback;
|
||||
|
||||
_GLFWcursor* currentCursor;
|
||||
} _GLFWwindowWayland;
|
||||
|
||||
|
||||
@ -78,10 +78,16 @@ typedef struct _GLFWlibraryWayland
|
||||
struct wl_registry* registry;
|
||||
struct wl_compositor* compositor;
|
||||
struct wl_shell* shell;
|
||||
struct wl_shm* shm;
|
||||
struct wl_seat* seat;
|
||||
struct wl_pointer* pointer;
|
||||
struct wl_keyboard* keyboard;
|
||||
|
||||
struct wl_cursor_theme* cursorTheme;
|
||||
struct wl_cursor* defaultCursor;
|
||||
struct wl_surface* cursorSurface;
|
||||
uint32_t pointerSerial;
|
||||
|
||||
_GLFWmonitor** monitors;
|
||||
int monitorsCount;
|
||||
int monitorsSize;
|
||||
@ -124,8 +130,9 @@ typedef struct _GLFWmonitorWayland
|
||||
//
|
||||
typedef struct _GLFWcursorWayland
|
||||
{
|
||||
int dummy;
|
||||
|
||||
struct wl_buffer* buffer;
|
||||
int width, height;
|
||||
int xhot, yhot;
|
||||
} _GLFWcursorWayland;
|
||||
|
||||
|
||||
|
219
src/wl_window.c
219
src/wl_window.c
@ -27,9 +27,16 @@
|
||||
#include "internal.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <poll.h>
|
||||
#include <GL/gl.h>
|
||||
#include <wayland-egl.h>
|
||||
#include <wayland-cursor.h>
|
||||
|
||||
|
||||
static void handlePing(void* data,
|
||||
@ -93,6 +100,105 @@ static GLboolean createSurface(_GLFWwindow* window,
|
||||
return GL_TRUE;
|
||||
}
|
||||
|
||||
static int
|
||||
set_cloexec_or_close(int fd)
|
||||
{
|
||||
long flags;
|
||||
|
||||
if (fd == -1)
|
||||
return -1;
|
||||
|
||||
flags = fcntl(fd, F_GETFD);
|
||||
if (flags == -1)
|
||||
goto err;
|
||||
|
||||
if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1)
|
||||
goto err;
|
||||
|
||||
return fd;
|
||||
|
||||
err:
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
create_tmpfile_cloexec(char *tmpname)
|
||||
{
|
||||
int fd;
|
||||
|
||||
#ifdef HAVE_MKOSTEMP
|
||||
fd = mkostemp(tmpname, O_CLOEXEC);
|
||||
if (fd >= 0)
|
||||
unlink(tmpname);
|
||||
#else
|
||||
fd = mkstemp(tmpname);
|
||||
if (fd >= 0) {
|
||||
fd = set_cloexec_or_close(fd);
|
||||
unlink(tmpname);
|
||||
}
|
||||
#endif
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a new, unique, anonymous file of the given size, and
|
||||
* return the file descriptor for it. The file descriptor is set
|
||||
* CLOEXEC. The file is immediately suitable for mmap()'ing
|
||||
* the given size at offset zero.
|
||||
*
|
||||
* The file should not have a permanent backing store like a disk,
|
||||
* but may have if XDG_RUNTIME_DIR is not properly implemented in OS.
|
||||
*
|
||||
* The file name is deleted from the file system.
|
||||
*
|
||||
* The file is suitable for buffer sharing between processes by
|
||||
* transmitting the file descriptor over Unix sockets using the
|
||||
* SCM_RIGHTS methods.
|
||||
*
|
||||
* If the C library implements posix_fallocate(), it is used to
|
||||
* guarantee that disk space is available for the file at the
|
||||
* given size. If disk space is insufficent, errno is set to ENOSPC.
|
||||
* If posix_fallocate() is not supported, program may receive
|
||||
* SIGBUS on accessing mmap()'ed file contents instead.
|
||||
*/
|
||||
int
|
||||
os_create_anonymous_file(off_t size)
|
||||
{
|
||||
static const char template[] = "/glfw-shared-XXXXXX";
|
||||
const char *path;
|
||||
char *name;
|
||||
int fd;
|
||||
int ret;
|
||||
|
||||
path = getenv("XDG_RUNTIME_DIR");
|
||||
if (!path) {
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
name = malloc(strlen(path) + sizeof(template));
|
||||
if (!name)
|
||||
return -1;
|
||||
|
||||
strcpy(name, path);
|
||||
strcat(name, template);
|
||||
|
||||
fd = create_tmpfile_cloexec(name);
|
||||
|
||||
free(name);
|
||||
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
ret = posix_fallocate(fd, 0, size);
|
||||
if (ret != 0) {
|
||||
close(fd);
|
||||
errno = ret;
|
||||
return -1;
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW platform API //////
|
||||
@ -122,6 +228,8 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window,
|
||||
wl_shell_surface_set_toplevel(window->wl.shell_surface);
|
||||
}
|
||||
|
||||
window->wl.currentCursor = NULL;
|
||||
|
||||
return GL_TRUE;
|
||||
}
|
||||
|
||||
@ -279,37 +387,116 @@ void _glfwPlatformSetCursorPos(_GLFWwindow* window, double x, double y)
|
||||
|
||||
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;
|
||||
}
|
||||
_glfwPlatformSetCursor(window, window->wl.currentCursor);
|
||||
}
|
||||
|
||||
int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
|
||||
const GLFWimage* image,
|
||||
int xhot, int yhot)
|
||||
{
|
||||
fprintf(stderr, "_glfwPlatformCreateCursor not implemented yet\n");
|
||||
struct wl_shm_pool *pool;
|
||||
int stride = image->width * 4;
|
||||
int length = image->width * image->height * 4;
|
||||
void *data;
|
||||
int fd, i;
|
||||
|
||||
fd = os_create_anonymous_file(length);
|
||||
if (fd < 0) {
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Wayland: Creating a buffer file for %d B failed: %m\n",
|
||||
length);
|
||||
return GL_FALSE;
|
||||
}
|
||||
|
||||
data = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
if (data == MAP_FAILED) {
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Wayland: Cursor mmap failed: %m\n");
|
||||
close(fd);
|
||||
return GL_FALSE;
|
||||
}
|
||||
|
||||
pool = wl_shm_create_pool(_glfw.wl.shm, fd, length);
|
||||
|
||||
close(fd);
|
||||
unsigned char* source = (unsigned char*) image->pixels;
|
||||
unsigned char* target = data;
|
||||
for (i = 0; i < image->width * image->height; i++, source += 4)
|
||||
{
|
||||
*target++ = source[2];
|
||||
*target++ = source[1];
|
||||
*target++ = source[0];
|
||||
*target++ = source[3];
|
||||
}
|
||||
|
||||
cursor->wl.buffer = wl_shm_pool_create_buffer(pool, 0,
|
||||
image->width,
|
||||
image->height,
|
||||
stride, WL_SHM_FORMAT_ARGB8888);
|
||||
munmap(data, length);
|
||||
wl_shm_pool_destroy(pool);
|
||||
|
||||
cursor->wl.width = image->width;
|
||||
cursor->wl.height = image->height;
|
||||
cursor->wl.xhot = xhot;
|
||||
cursor->wl.yhot = yhot;
|
||||
return GL_TRUE;
|
||||
}
|
||||
|
||||
void _glfwPlatformDestroyCursor(_GLFWcursor* cursor)
|
||||
{
|
||||
fprintf(stderr, "_glfwPlatformDestroyCursor not implemented yet\n");
|
||||
wl_buffer_destroy(cursor->wl.buffer);
|
||||
}
|
||||
|
||||
void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor)
|
||||
{
|
||||
fprintf(stderr, "_glfwPlatformSetCursor not implemented yet\n");
|
||||
struct wl_buffer *buffer;
|
||||
struct wl_cursor_image *image;
|
||||
struct wl_surface *surface = _glfw.wl.cursorSurface;
|
||||
|
||||
if (!_glfw.wl.pointer)
|
||||
return;
|
||||
|
||||
window->wl.currentCursor = cursor;
|
||||
|
||||
// If we're not in the correct window just save the cursor
|
||||
// the next time the pointer enters the window the cursor will change
|
||||
if (window != _glfw.wl.pointerFocus)
|
||||
return;
|
||||
|
||||
if (window->cursorMode == GLFW_CURSOR_NORMAL)
|
||||
{
|
||||
if (cursor == NULL)
|
||||
{
|
||||
image = _glfw.wl.defaultCursor->images[0];
|
||||
buffer = wl_cursor_image_get_buffer(image);
|
||||
if (!buffer)
|
||||
return;
|
||||
wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerSerial,
|
||||
surface,
|
||||
image->hotspot_x,
|
||||
image->hotspot_y);
|
||||
wl_surface_attach(surface, buffer, 0, 0);
|
||||
wl_surface_damage(surface, 0, 0,
|
||||
image->width, image->height);
|
||||
wl_surface_commit(surface);
|
||||
}
|
||||
else
|
||||
{
|
||||
wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerSerial,
|
||||
surface,
|
||||
cursor->wl.xhot,
|
||||
cursor->wl.yhot);
|
||||
wl_surface_attach(surface, cursor->wl.buffer, 0, 0);
|
||||
wl_surface_damage(surface, 0, 0,
|
||||
cursor->wl.width, cursor->wl.height);
|
||||
wl_surface_commit(surface);
|
||||
}
|
||||
}
|
||||
else /* Cursor is hidden set cursor surface to NULL */
|
||||
{
|
||||
wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerSerial, NULL, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string)
|
||||
|
Loading…
Reference in New Issue
Block a user