//======================================================================== // GLFW 3.1 Wayland - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2014 Jonas Ã…dahl // // 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 #include #include #include #include #include #include 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 pointerHandleEnter(void* data, struct wl_pointer* pointer, uint32_t serial, struct wl_surface* surface, wl_fixed_t sx, wl_fixed_t sy) { _GLFWwindow* window = wl_surface_get_user_data(surface); _glfw.wl.pointerFocus = window; _glfwInputCursorEnter(window, GL_TRUE); } static void pointerHandleLeave(void* data, struct wl_pointer* pointer, uint32_t serial, struct wl_surface* surface) { _GLFWwindow* window = wl_surface_get_user_data(surface); _glfw.wl.pointerFocus = NULL; _glfwInputCursorEnter(window, GL_FALSE); } static void pointerHandleMotion(void* data, struct wl_pointer* pointer, uint32_t time, wl_fixed_t sx, wl_fixed_t sy) { _GLFWwindow* window = _glfw.wl.pointerFocus; if (window->cursorMode == GLFW_CURSOR_DISABLED) { /* TODO */ _glfwInputError(GLFW_PLATFORM_ERROR, "Wayland: GLFW_CURSOR_DISABLED not supported"); return; } _glfwInputCursorMotion(window, wl_fixed_to_double(sx), wl_fixed_to_double(sy)); } static void pointerHandleButton(void* data, struct wl_pointer* wl_pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t state) { _GLFWwindow* window = _glfw.wl.pointerFocus; int glfwButton; /* Makes left, right and middle 0, 1 and 2. Overall order follows evdev * codes. */ glfwButton = button - BTN_LEFT; /* TODO: modifiers */ _glfwInputMouseClick(window, glfwButton, state == WL_POINTER_BUTTON_STATE_PRESSED ? GLFW_PRESS : GLFW_RELEASE, 0); } static void pointerHandleAxis(void* data, struct wl_pointer* wl_pointer, uint32_t time, uint32_t axis, wl_fixed_t value) { _GLFWwindow* window = _glfw.wl.pointerFocus; double scroll_factor; double x, y; /* Wayland scroll events are in pointer motion coordinate space (think * two finger scroll). The factor 10 is commonly used to convert to * "scroll step means 1.0. */ scroll_factor = 1.0/10.0; switch (axis) { case WL_POINTER_AXIS_HORIZONTAL_SCROLL: x = wl_fixed_to_double(value) * scroll_factor; y = 0.0; break; case WL_POINTER_AXIS_VERTICAL_SCROLL: x = 0.0; y = wl_fixed_to_double(value) * scroll_factor; break; default: break; } _glfwInputScroll(window, x, y); } static const struct wl_pointer_listener pointerListener = { pointerHandleEnter, pointerHandleLeave, pointerHandleMotion, pointerHandleButton, pointerHandleAxis, }; static void keyboardHandleKeymap(void* data, struct wl_keyboard* keyboard, uint32_t format, int fd, uint32_t size) { /* TODO */ } static void keyboardHandleEnter(void* data, struct wl_keyboard* keyboard, uint32_t serial, struct wl_surface* surface, struct wl_array* keys) { _glfwInputWindowFocus(wl_surface_get_user_data(surface), GL_TRUE); } static void keyboardHandleLeave(void* data, struct wl_keyboard* keyboard, uint32_t serial, struct wl_surface* surface) { _glfwInputWindowFocus(wl_surface_get_user_data(surface), GL_FALSE); } static void keyboardHandleKey(void* data, struct wl_keyboard* keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state) { /* TODO */ } static void keyboardHandleModifiers(void* data, struct wl_keyboard* keyboard, uint32_t serial, uint32_t modsDepressed, uint32_t modsLatched, uint32_t modsLocked, uint32_t group) { /* TODO */ } static const struct wl_keyboard_listener keyboardListener = { keyboardHandleKeymap, keyboardHandleEnter, keyboardHandleLeave, keyboardHandleKey, keyboardHandleModifiers, }; static void seatHandleCapabilities(void* data, struct wl_seat* seat, enum wl_seat_capability caps) { if ((caps & WL_SEAT_CAPABILITY_POINTER) && !_glfw.wl.pointer) { _glfw.wl.pointer = wl_seat_get_pointer(seat); wl_pointer_add_listener(_glfw.wl.pointer, &pointerListener, NULL); } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && _glfw.wl.pointer) { wl_pointer_destroy(_glfw.wl.pointer); _glfw.wl.pointer = NULL; } if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !_glfw.wl.keyboard) { _glfw.wl.keyboard = wl_seat_get_keyboard(seat); wl_keyboard_add_listener(_glfw.wl.keyboard, &keyboardListener, NULL); } else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && _glfw.wl.keyboard) { wl_keyboard_destroy(_glfw.wl.keyboard); _glfw.wl.keyboard = NULL; } } static const struct wl_seat_listener seatListener = { seatHandleCapabilities }; static void registryHandleGlobal(void* data, struct wl_registry* registry, uint32_t name, const char* interface, uint32_t version) { if (strcmp(interface, "wl_compositor") == 0) { _glfw.wl.compositor = wl_registry_bind(registry, name, &wl_compositor_interface, 1); } else if (strcmp(interface, "wl_shell") == 0) { _glfw.wl.shell = wl_registry_bind(registry, name, &wl_shell_interface, 1); } else if (strcmp(interface, "wl_output") == 0) { _glfwAddOutput(name, version); } else if (strcmp(interface, "wl_seat") == 0) { if (!_glfw.wl.seat) { _glfw.wl.seat = wl_registry_bind(registry, name, &wl_seat_interface, 1); wl_seat_add_listener(_glfw.wl.seat, &seatListener, NULL); } } } 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.wl.display = wl_display_connect(NULL); if (!_glfw.wl.display) { _glfwInputError(GLFW_PLATFORM_ERROR, "Wayland: Failed to connect to display"); return GL_FALSE; } _glfw.wl.registry = wl_display_get_registry(_glfw.wl.display); wl_registry_add_listener(_glfw.wl.registry, ®istryListener, NULL); _glfw.wl.monitors = calloc(4, sizeof(_GLFWmonitor*)); _glfw.wl.monitorsSize = 4; // Sync so we got all registry objects wl_display_roundtrip(_glfw.wl.display); // Sync so we got all initial output events wl_display_roundtrip(_glfw.wl.display); if (!_glfwInitContextAPI()) return GL_FALSE; _glfwInitTimer(); _glfwInitJoysticks(); return GL_TRUE; } void _glfwPlatformTerminate(void) { _glfwTerminateContextAPI(); if (_glfw.wl.registry) wl_registry_destroy(_glfw.wl.registry); if (_glfw.wl.display) wl_display_flush(_glfw.wl.display); if (_glfw.wl.display) wl_display_disconnect(_glfw.wl.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; }