This commit is contained in:
ninja 2021-05-14 19:45:39 +02:00 committed by GitHub
commit 249832ce14
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 334 additions and 59 deletions

View File

@ -8,7 +8,7 @@ branches:
matrix: matrix:
include: include:
- os: linux - os: linux
dist: xenial dist: focal
name: "X11 shared library" name: "X11 shared library"
addons: addons:
apt: apt:
@ -22,7 +22,7 @@ matrix:
- BUILD_SHARED_LIBS=ON - BUILD_SHARED_LIBS=ON
- CFLAGS=-Werror - CFLAGS=-Werror
- os: linux - os: linux
dist: xenial dist: focal
name: "X11 static library" name: "X11 static library"
addons: addons:
apt: apt:
@ -45,6 +45,8 @@ matrix:
- libwayland-dev - libwayland-dev
- libxkbcommon-dev - libxkbcommon-dev
- libegl1-mesa-dev - libegl1-mesa-dev
- meson
- libdbus-1-dev
env: env:
- USE_WAYLAND=ON - USE_WAYLAND=ON
- BUILD_SHARED_LIBS=ON - BUILD_SHARED_LIBS=ON
@ -59,12 +61,14 @@ matrix:
- libwayland-dev - libwayland-dev
- libxkbcommon-dev - libxkbcommon-dev
- libegl1-mesa-dev - libegl1-mesa-dev
- meson
- libdbus-1-dev
env: env:
- USE_WAYLAND=ON - USE_WAYLAND=ON
- BUILD_SHARED_LIBS=OFF - BUILD_SHARED_LIBS=OFF
- CFLAGS=-Werror - CFLAGS=-Werror
- os: linux - os: linux
dist: bionic dist: focal
name: "Null shared library" name: "Null shared library"
addons: addons:
apt: apt:
@ -75,7 +79,7 @@ matrix:
- USE_OSMESA=ON - USE_OSMESA=ON
- CFLAGS=-Werror - CFLAGS=-Werror
- os: linux - os: linux
dist: bionic dist: focal
name: "Null static library" name: "Null static library"
addons: addons:
apt: apt:

View File

@ -40,6 +40,8 @@ cmake_dependent_option(GLFW_USE_WAYLAND "Use Wayland for window creation" OFF
"UNIX;NOT APPLE" OFF) "UNIX;NOT APPLE" OFF)
cmake_dependent_option(USE_MSVC_RUNTIME_LIBRARY_DLL "Use MSVC runtime library DLL" ON cmake_dependent_option(USE_MSVC_RUNTIME_LIBRARY_DLL "Use MSVC runtime library DLL" ON
"MSVC" OFF) "MSVC" OFF)
cmake_dependent_option(GLFW_USE_LIBDECORATION "use libdecoration" ON
"GLFW_USE_WAYLAND" OFF)
if (BUILD_SHARED_LIBS AND UNIX) if (BUILD_SHARED_LIBS AND UNIX)
# On Unix-like systems, shared libraries can use the soname system. # On Unix-like systems, shared libraries can use the soname system.
@ -59,6 +61,8 @@ endif()
list(APPEND CMAKE_MODULE_PATH "${GLFW_SOURCE_DIR}/CMake/modules") list(APPEND CMAKE_MODULE_PATH "${GLFW_SOURCE_DIR}/CMake/modules")
include(ExternalProject)
find_package(Threads REQUIRED) find_package(Threads REQUIRED)
if (GLFW_BUILD_DOCS) if (GLFW_BUILD_DOCS)
@ -66,6 +70,23 @@ if (GLFW_BUILD_DOCS)
find_package(Doxygen) find_package(Doxygen)
endif() endif()
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} \
-fsanitize=address \
-fsanitize=bool \
-fsanitize=bounds \
-fsanitize=enum \
-fsanitize=float-cast-overflow \
-fsanitize=float-divide-by-zero \
-fsanitize=nonnull-attribute \
-fsanitize=returns-nonnull-attribute \
-fsanitize=signed-integer-overflow \
-fsanitize=undefined \
-fsanitize=vla-bound \
-fno-sanitize=alignment \
-fsanitize=leak \
-fsanitize=object-size \
")
#-------------------------------------------------------------------- #--------------------------------------------------------------------
# Set compiler specific flags # Set compiler specific flags
#-------------------------------------------------------------------- #--------------------------------------------------------------------

13
external/libdecoration.cmake vendored Normal file
View File

@ -0,0 +1,13 @@
ExternalProject_Add(libdecoration
GIT_REPOSITORY https://gitlab.gnome.org/jadahl/libdecoration.git
GIT_TAG master
PREFIX "${CMAKE_CURRENT_BINARY_DIR}/extern/libdecoration"
CONFIGURE_COMMAND meson --prefix "${CMAKE_CURRENT_BINARY_DIR}/install" --libdir "lib" ../libdecoration
BUILD_COMMAND ninja
INSTALL_COMMAND ninja install
)
target_include_directories(glfw PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/install/include")
target_link_libraries(glfw PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/install/lib/libdecoration${CMAKE_SHARED_LIBRARY_SUFFIX})
add_dependencies(glfw libdecoration)

View File

@ -175,6 +175,14 @@ static GLFWbool chooseEGLConfig(const _GLFWctxconfig* ctxconfig,
u->samples = getEGLConfigAttrib(n, EGL_SAMPLES); u->samples = getEGLConfigAttrib(n, EGL_SAMPLES);
u->doublebuffer = desired->doublebuffer; u->doublebuffer = desired->doublebuffer;
#if defined(_GLFW_WAYLAND)
// Avoid using transparent buffer on Wayland if transparency is not requested.
// Otherwise mutter will fail to properly screenshot OpenGL content.
if (u->alphaBits > 0 && !desired->transparent) {
continue;
}
#endif // _GLFW_WAYLAND
u->handle = (uintptr_t) n; u->handle = (uintptr_t) n;
usableCount++; usableCount++;
} }

View File

@ -44,11 +44,14 @@
#include <wayland-client.h> #include <wayland-client.h>
const char *proxy_tag = "glfw-surface";
static inline int min(int n1, int n2) static inline int min(int n1, int n2)
{ {
return n1 < n2 ? n1 : n2; return n1 < n2 ? n1 : n2;
} }
#ifndef WITH_DECORATION
static _GLFWwindow* findWindowFromDecorationSurface(struct wl_surface* surface, static _GLFWwindow* findWindowFromDecorationSurface(struct wl_surface* surface,
int* which) int* which)
{ {
@ -82,6 +85,20 @@ static _GLFWwindow* findWindowFromDecorationSurface(struct wl_surface* surface,
} }
return window; return window;
} }
#endif
#ifdef WITH_DECORATION
void decoration_error(struct libdecor *context,
enum libdecor_error error,
const char *message)
{
_glfwInputError(GLFW_PLATFORM_ERROR, "Wayland: Caught error (%d): %s\n", error, message);
}
static struct libdecor_interface decoration_interface = {
decoration_error,
};
#endif
static void pointerHandleEnter(void* data, static void pointerHandleEnter(void* data,
struct wl_pointer* pointer, struct wl_pointer* pointer,
@ -94,8 +111,16 @@ static void pointerHandleEnter(void* data,
if (!surface) if (!surface)
return; return;
int focus = 0; if (wl_proxy_get_tag((struct wl_proxy *) surface) != &proxy_tag)
return;
_GLFWwindow* window = wl_surface_get_user_data(surface); _GLFWwindow* window = wl_surface_get_user_data(surface);
#ifdef WITH_DECORATION
if (surface != window->wl.surface)
return;
#else
int focus = 0;
if (!window) if (!window)
{ {
window = findWindowFromDecorationSurface(surface, &focus); window = findWindowFromDecorationSurface(surface, &focus);
@ -104,6 +129,8 @@ static void pointerHandleEnter(void* data,
} }
window->wl.decorations.focus = focus; window->wl.decorations.focus = focus;
#endif
_glfw.wl.serial = serial; _glfw.wl.serial = serial;
_glfw.wl.pointerFocus = window; _glfw.wl.pointerFocus = window;
@ -191,9 +218,16 @@ static void pointerHandleMotion(void* data,
if (window->cursorMode == GLFW_CURSOR_DISABLED) if (window->cursorMode == GLFW_CURSOR_DISABLED)
return; return;
x = wl_fixed_to_double(sx); x = wl_fixed_to_double(sx);
y = wl_fixed_to_double(sy); y = wl_fixed_to_double(sy);
#ifdef WITH_DECORATION
window->wl.cursorPosX = x;
window->wl.cursorPosY = y;
_glfwInputCursorPos(window, x, y);
_glfw.wl.cursorPreviousName = NULL;
#else
switch (window->wl.decorations.focus) switch (window->wl.decorations.focus)
{ {
case mainWindow: case mainWindow:
@ -231,6 +265,7 @@ static void pointerHandleMotion(void* data,
default: default:
assert(0); assert(0);
} }
#endif
if (_glfw.wl.cursorPreviousName != cursorName) if (_glfw.wl.cursorPreviousName != cursorName)
setCursor(window, cursorName); setCursor(window, cursorName);
} }
@ -244,10 +279,11 @@ static void pointerHandleButton(void* data,
{ {
_GLFWwindow* window = _glfw.wl.pointerFocus; _GLFWwindow* window = _glfw.wl.pointerFocus;
int glfwButton; int glfwButton;
uint32_t edges = XDG_TOPLEVEL_RESIZE_EDGE_NONE;
if (!window) if (!window)
return; return;
#ifndef WITH_DECORATION
uint32_t edges = XDG_TOPLEVEL_RESIZE_EDGE_NONE;
if (button == BTN_LEFT) if (button == BTN_LEFT)
{ {
switch (window->wl.decorations.focus) switch (window->wl.decorations.focus)
@ -306,6 +342,7 @@ static void pointerHandleButton(void* data,
// Dont pass the button to the user if it was related to a decoration. // Dont pass the button to the user if it was related to a decoration.
if (window->wl.decorations.focus != mainWindow) if (window->wl.decorations.focus != mainWindow)
return; return;
#endif
_glfw.wl.serial = serial; _glfw.wl.serial = serial;
@ -469,12 +506,17 @@ static void keyboardHandleEnter(void* data,
return; return;
_GLFWwindow* window = wl_surface_get_user_data(surface); _GLFWwindow* window = wl_surface_get_user_data(surface);
#ifdef WITH_DECORATION
if (surface != window->wl.surface)
return;
#else
if (!window) if (!window)
{ {
window = findWindowFromDecorationSurface(surface, NULL); window = findWindowFromDecorationSurface(surface, NULL);
if (!window) if (!window)
return; return;
} }
#endif
_glfw.wl.serial = serial; _glfw.wl.serial = serial;
_glfw.wl.keyboardFocus = window; _glfw.wl.keyboardFocus = window;
@ -769,6 +811,7 @@ static const struct wl_data_device_listener dataDeviceListener = {
dataDeviceHandleSelection, dataDeviceHandleSelection,
}; };
#ifndef WITH_DECORATION
static void wmBaseHandlePing(void* data, static void wmBaseHandlePing(void* data,
struct xdg_wm_base* wmBase, struct xdg_wm_base* wmBase,
uint32_t serial) uint32_t serial)
@ -779,6 +822,7 @@ static void wmBaseHandlePing(void* data,
static const struct xdg_wm_base_listener wmBaseListener = { static const struct xdg_wm_base_listener wmBaseListener = {
wmBaseHandlePing wmBaseHandlePing
}; };
#endif
static void registryHandleGlobal(void* data, static void registryHandleGlobal(void* data,
struct wl_registry* registry, struct wl_registry* registry,
@ -827,6 +871,7 @@ static void registryHandleGlobal(void* data,
&wl_data_device_manager_interface, 1); &wl_data_device_manager_interface, 1);
} }
} }
#ifndef WITH_DECORATION
else if (strcmp(interface, "xdg_wm_base") == 0) else if (strcmp(interface, "xdg_wm_base") == 0)
{ {
_glfw.wl.wmBase = _glfw.wl.wmBase =
@ -845,6 +890,7 @@ static void registryHandleGlobal(void* data,
_glfw.wl.viewporter = _glfw.wl.viewporter =
wl_registry_bind(registry, name, &wp_viewporter_interface, 1); wl_registry_bind(registry, name, &wp_viewporter_interface, 1);
} }
#endif
else if (strcmp(interface, "zwp_relative_pointer_manager_v1") == 0) else if (strcmp(interface, "zwp_relative_pointer_manager_v1") == 0)
{ {
_glfw.wl.relativePointerManager = _glfw.wl.relativePointerManager =
@ -1150,14 +1196,16 @@ int _glfwPlatformInit(void)
_glfw.wl.timerfd = -1; _glfw.wl.timerfd = -1;
if (_glfw.wl.seatVersion >= 4) if (_glfw.wl.seatVersion >= 4)
_glfw.wl.timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC); _glfw.wl.timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK);
#ifndef WITH_DECORATION
if (!_glfw.wl.wmBase) if (!_glfw.wl.wmBase)
{ {
_glfwInputError(GLFW_PLATFORM_ERROR, _glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: Failed to find xdg-shell in your compositor"); "Wayland: Failed to find xdg-shell in your compositor");
return GLFW_FALSE; return GLFW_FALSE;
} }
#endif
if (_glfw.wl.pointer && _glfw.wl.shm) if (_glfw.wl.pointer && _glfw.wl.shm)
{ {
@ -1203,6 +1251,10 @@ int _glfwPlatformInit(void)
_glfw.wl.clipboardSize = 4096; _glfw.wl.clipboardSize = 4096;
} }
#ifdef WITH_DECORATION
_glfw.wl.csd_context = libdecor_new(_glfw.wl.display, &decoration_interface);
#endif
return GLFW_TRUE; return GLFW_TRUE;
} }
@ -1249,12 +1301,17 @@ void _glfwPlatformTerminate(void)
wl_compositor_destroy(_glfw.wl.compositor); wl_compositor_destroy(_glfw.wl.compositor);
if (_glfw.wl.shm) if (_glfw.wl.shm)
wl_shm_destroy(_glfw.wl.shm); wl_shm_destroy(_glfw.wl.shm);
#ifdef WITH_DECORATION
if (_glfw.wl.csd_context)
libdecor_unref(_glfw.wl.csd_context);
#else
if (_glfw.wl.viewporter) if (_glfw.wl.viewporter)
wp_viewporter_destroy(_glfw.wl.viewporter); wp_viewporter_destroy(_glfw.wl.viewporter);
if (_glfw.wl.decorationManager) if (_glfw.wl.decorationManager)
zxdg_decoration_manager_v1_destroy(_glfw.wl.decorationManager); zxdg_decoration_manager_v1_destroy(_glfw.wl.decorationManager);
if (_glfw.wl.wmBase) if (_glfw.wl.wmBase)
xdg_wm_base_destroy(_glfw.wl.wmBase); xdg_wm_base_destroy(_glfw.wl.wmBase);
#endif
if (_glfw.wl.dataSource) if (_glfw.wl.dataSource)
wl_data_source_destroy(_glfw.wl.dataSource); wl_data_source_destroy(_glfw.wl.dataSource);
if (_glfw.wl.dataDevice) if (_glfw.wl.dataDevice)

View File

@ -54,13 +54,18 @@ typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR
#endif #endif
#include "xkb_unicode.h" #include "xkb_unicode.h"
#include "wayland-xdg-shell-client-protocol.h"
#include "wayland-xdg-decoration-client-protocol.h"
#include "wayland-viewporter-client-protocol.h"
#include "wayland-relative-pointer-unstable-v1-client-protocol.h" #include "wayland-relative-pointer-unstable-v1-client-protocol.h"
#include "wayland-pointer-constraints-unstable-v1-client-protocol.h" #include "wayland-pointer-constraints-unstable-v1-client-protocol.h"
#include "wayland-idle-inhibit-unstable-v1-client-protocol.h" #include "wayland-idle-inhibit-unstable-v1-client-protocol.h"
#ifdef WITH_DECORATION
#include <libdecoration/libdecoration.h>
#else
#include "wayland-xdg-shell-client-protocol.h"
#include "wayland-xdg-decoration-client-protocol.h"
#include "wayland-viewporter-client-protocol.h"
#endif
#define _glfw_dlopen(name) dlopen(name, RTLD_LAZY | RTLD_LOCAL) #define _glfw_dlopen(name) dlopen(name, RTLD_LAZY | RTLD_LOCAL)
#define _glfw_dlclose(handle) dlclose(handle) #define _glfw_dlclose(handle) dlclose(handle)
#define _glfw_dlsym(handle, name) dlsym(handle, name) #define _glfw_dlsym(handle, name) dlsym(handle, name)
@ -146,6 +151,7 @@ typedef xkb_keysym_t (* PFN_xkb_compose_state_get_one_sym)(struct xkb_compose_st
#define _GLFW_DECORATION_VERTICAL (_GLFW_DECORATION_TOP + _GLFW_DECORATION_WIDTH) #define _GLFW_DECORATION_VERTICAL (_GLFW_DECORATION_TOP + _GLFW_DECORATION_WIDTH)
#define _GLFW_DECORATION_HORIZONTAL (2 * _GLFW_DECORATION_WIDTH) #define _GLFW_DECORATION_HORIZONTAL (2 * _GLFW_DECORATION_WIDTH)
#ifndef WITH_DECORATION
typedef enum _GLFWdecorationSideWayland typedef enum _GLFWdecorationSideWayland
{ {
mainWindow, mainWindow,
@ -163,6 +169,7 @@ typedef struct _GLFWdecorationWayland
struct wp_viewport* viewport; struct wp_viewport* viewport;
} _GLFWdecorationWayland; } _GLFWdecorationWayland;
#endif
// Wayland-specific per-window data // Wayland-specific per-window data
// //
@ -177,11 +184,13 @@ typedef struct _GLFWwindowWayland
struct wl_egl_window* native; struct wl_egl_window* native;
struct wl_callback* callback; struct wl_callback* callback;
#ifndef WITH_DECORATION
struct { struct {
struct xdg_surface* surface; struct xdg_surface* surface;
struct xdg_toplevel* toplevel; struct xdg_toplevel* toplevel;
struct zxdg_toplevel_decoration_v1* decoration; struct zxdg_toplevel_decoration_v1* decoration;
} xdg; } xdg;
#endif
_GLFWcursor* currentCursor; _GLFWcursor* currentCursor;
double cursorPosX, cursorPosY; double cursorPosX, cursorPosY;
@ -204,12 +213,16 @@ typedef struct _GLFWwindowWayland
GLFWbool wasFullscreen; GLFWbool wasFullscreen;
#ifndef WITH_DECORATION
struct { struct {
GLFWbool serverSide; GLFWbool serverSide;
struct wl_buffer* buffer; struct wl_buffer* buffer;
_GLFWdecorationWayland top, left, right, bottom; _GLFWdecorationWayland top, left, right, bottom;
int focus; int focus;
} decorations; } decorations;
#else
struct libdecor_frame *decoration_frame;
#endif
} _GLFWwindowWayland; } _GLFWwindowWayland;
@ -229,9 +242,13 @@ typedef struct _GLFWlibraryWayland
struct wl_data_device* dataDevice; struct wl_data_device* dataDevice;
struct wl_data_offer* dataOffer; struct wl_data_offer* dataOffer;
struct wl_data_source* dataSource; struct wl_data_source* dataSource;
#ifdef WITH_DECORATION
struct libdecor *csd_context;
#else
struct xdg_wm_base* wmBase; struct xdg_wm_base* wmBase;
struct zxdg_decoration_manager_v1* decorationManager; struct zxdg_decoration_manager_v1* decorationManager;
struct wp_viewporter* viewporter; struct wp_viewporter* viewporter;
#endif
struct zwp_relative_pointer_manager_v1* relativePointerManager; struct zwp_relative_pointer_manager_v1* relativePointerManager;
struct zwp_pointer_constraints_v1* pointerConstraints; struct zwp_pointer_constraints_v1* pointerConstraints;
struct zwp_idle_inhibit_manager_v1* idleInhibitManager; struct zwp_idle_inhibit_manager_v1* idleInhibitManager;

View File

@ -40,6 +40,12 @@
#include <sys/timerfd.h> #include <sys/timerfd.h>
#include <poll.h> #include <poll.h>
#ifdef WITH_DECORATION
#include <libdecoration/libdecoration.h>
#endif
extern const char *proxy_tag;
static int createTmpfileCloexec(char* tmpname) static int createTmpfileCloexec(char* tmpname)
{ {
@ -182,6 +188,61 @@ static struct wl_buffer* createShmBuffer(const GLFWimage* image)
return buffer; return buffer;
} }
#ifdef WITH_DECORATION
static void resizeWindow(_GLFWwindow* window);
void frame_configure(struct libdecor_frame *frame, struct libdecor_configuration *configuration, void *user_data)
{
_GLFWwindow* window = user_data;
int width, height;
if (!libdecor_configuration_get_content_size(configuration, frame, &width, &height)) {
width = window->wl.width;
height = window->wl.height;
}
window->wl.width = width;
window->wl.height = height;
resizeWindow(window);
_glfwInputWindowSize(window, width, height);
_glfwPlatformSetWindowSize(window, width, height);
_glfwInputWindowDamage(window);
struct libdecor_state *state = libdecor_state_new(width, height);
libdecor_frame_commit(frame, state, configuration);
libdecor_state_free(state);
}
void frame_close(struct libdecor_frame *frame, void *user_data)
{
_glfwInputWindowCloseRequest(user_data);
}
void frame_commit(void *user_data)
{
_GLFWwindow* window = user_data;
_glfwInputWindowDamage(window);
}
static struct libdecor_frame_interface frame_interface = {
frame_configure,
frame_close,
frame_commit,
};
#endif
#ifdef WITH_DECORATION
static void createDecorations(_GLFWwindow* window)
{
// TODO: enable decoration
}
static void destroyDecorations(_GLFWwindow* window)
{
// TODO: disable decoration
}
#else
static void createDecoration(_GLFWdecorationWayland* decoration, static void createDecoration(_GLFWdecorationWayland* decoration,
struct wl_surface* parent, struct wl_surface* parent,
struct wl_buffer* buffer, GLFWbool opaque, struct wl_buffer* buffer, GLFWbool opaque,
@ -264,22 +325,23 @@ static void destroyDecorations(_GLFWwindow* window)
destroyDecoration(&window->wl.decorations.right); destroyDecoration(&window->wl.decorations.right);
destroyDecoration(&window->wl.decorations.bottom); destroyDecoration(&window->wl.decorations.bottom);
} }
#endif
#ifndef WITH_DECORATION
static void xdgDecorationHandleConfigure(void* data, static void xdgDecorationHandleConfigure(void* data,
struct zxdg_toplevel_decoration_v1* decoration, struct zxdg_toplevel_decoration_v1* decoration,
uint32_t mode) uint32_t mode)
{ {
_GLFWwindow* window = data; _GLFWwindow* window = data;
window->wl.decorations.serverSide = (mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); if (!(window->wl.decorations.serverSide = (mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE)))
if (!window->wl.decorations.serverSide)
createDecorations(window); createDecorations(window);
} }
static const struct zxdg_toplevel_decoration_v1_listener xdgDecorationListener = { static const struct zxdg_toplevel_decoration_v1_listener xdgDecorationListener = {
xdgDecorationHandleConfigure, xdgDecorationHandleConfigure,
}; };
#endif
// Makes the surface considered as XRGB instead of ARGB. // Makes the surface considered as XRGB instead of ARGB.
static void setOpaqueRegion(_GLFWwindow* window) static void setOpaqueRegion(_GLFWwindow* window)
@ -308,6 +370,7 @@ static void resizeWindow(_GLFWwindow* window)
_glfwInputFramebufferSize(window, scaledWidth, scaledHeight); _glfwInputFramebufferSize(window, scaledWidth, scaledHeight);
_glfwInputWindowContentScale(window, scale, scale); _glfwInputWindowContentScale(window, scale, scale);
#ifndef WITH_DECORATION
if (!window->wl.decorations.top.surface) if (!window->wl.decorations.top.surface)
return; return;
@ -334,6 +397,7 @@ static void resizeWindow(_GLFWwindow* window)
wp_viewport_set_destination(window->wl.decorations.bottom.viewport, wp_viewport_set_destination(window->wl.decorations.bottom.viewport,
window->wl.width + _GLFW_DECORATION_HORIZONTAL, _GLFW_DECORATION_WIDTH); window->wl.width + _GLFW_DECORATION_HORIZONTAL, _GLFW_DECORATION_WIDTH);
wl_surface_commit(window->wl.decorations.bottom.surface); wl_surface_commit(window->wl.decorations.bottom.surface);
#endif
} }
static void checkScaleChange(_GLFWwindow* window) static void checkScaleChange(_GLFWwindow* window)
@ -427,8 +491,7 @@ static void setIdleInhibitor(_GLFWwindow* window, GLFWbool enable)
} }
} }
static GLFWbool createSurface(_GLFWwindow* window, static GLFWbool createSurface(_GLFWwindow* window)
const _GLFWwndconfig* wndconfig)
{ {
window->wl.surface = wl_compositor_create_surface(_glfw.wl.compositor); window->wl.surface = wl_compositor_create_surface(_glfw.wl.compositor);
if (!window->wl.surface) if (!window->wl.surface)
@ -439,37 +502,60 @@ static GLFWbool createSurface(_GLFWwindow* window,
window); window);
wl_surface_set_user_data(window->wl.surface, window); wl_surface_set_user_data(window->wl.surface, window);
wl_proxy_set_tag((struct wl_proxy *) window->wl.surface, &proxy_tag);
wl_display_roundtrip(_glfw.wl.display);
wl_display_roundtrip(_glfw.wl.display);
window->wl.native = wl_egl_window_create(window->wl.surface, window->wl.native = wl_egl_window_create(window->wl.surface,
wndconfig->width, window->wl.width,
wndconfig->height); window->wl.height);
if (!window->wl.native) if (!window->wl.native)
return GLFW_FALSE; return GLFW_FALSE;
window->wl.width = wndconfig->width;
window->wl.height = wndconfig->height;
window->wl.scale = 1;
if (!window->wl.transparent) if (!window->wl.transparent)
setOpaqueRegion(window); setOpaqueRegion(window);
return GLFW_TRUE; return GLFW_TRUE;
} }
#ifdef WITH_DECORATION
static GLFWbool createSurfaceDecoration(_GLFWwindow* window)
{
window->wl.decoration_frame = libdecor_decorate(_glfw.wl.csd_context,
window->wl.surface,
&frame_interface,
window);
libdecor_frame_map(window->wl.decoration_frame);
window->wl.scale = 1;
return GLFW_TRUE;
}
#endif
static void setFullscreen(_GLFWwindow* window, _GLFWmonitor* monitor, static void setFullscreen(_GLFWwindow* window, _GLFWmonitor* monitor,
int refreshRate) int refreshRate)
{ {
#ifdef WITH_DECORATION
libdecor_frame_set_fullscreen(window->wl.decoration_frame, monitor->wl.output);
#else
if (window->wl.xdg.toplevel) if (window->wl.xdg.toplevel)
{ {
xdg_toplevel_set_fullscreen( xdg_toplevel_set_fullscreen(
window->wl.xdg.toplevel, window->wl.xdg.toplevel,
monitor->wl.output); monitor->wl.output);
} }
#endif
setIdleInhibitor(window, GLFW_TRUE); setIdleInhibitor(window, GLFW_TRUE);
#ifndef WITH_DECORATION
if (!window->wl.decorations.serverSide) if (!window->wl.decorations.serverSide)
destroyDecorations(window); destroyDecorations(window);
#endif
} }
#ifndef WITH_DECORATION
static void xdgToplevelHandleConfigure(void* data, static void xdgToplevelHandleConfigure(void* data,
struct xdg_toplevel* toplevel, struct xdg_toplevel* toplevel,
int32_t width, int32_t width,
@ -639,6 +725,7 @@ static GLFWbool createXdgSurface(_GLFWwindow* window)
return GLFW_TRUE; return GLFW_TRUE;
} }
#endif
static void setCursorImage(_GLFWwindow* window, static void setCursorImage(_GLFWwindow* window,
_GLFWcursorWayland* cursorWayland) _GLFWcursorWayland* cursorWayland)
@ -690,8 +777,12 @@ static void incrementCursorImage(_GLFWwindow* window)
{ {
_GLFWcursor* cursor; _GLFWcursor* cursor;
if (!window || window->wl.decorations.focus != mainWindow) if (!window) return;
#ifndef WITH_DECORATION
if (window->wl.decorations.focus != mainWindow)
return; return;
#endif
cursor = window->wl.currentCursor; cursor = window->wl.currentCursor;
if (cursor && cursor->wl.cursor) if (cursor && cursor->wl.cursor)
@ -788,7 +879,17 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window,
{ {
window->wl.transparent = fbconfig->transparent; window->wl.transparent = fbconfig->transparent;
if (!createSurface(window, wndconfig)) window->wl.visible = wndconfig->visible;
window->wl.width = wndconfig->width;
window->wl.height = wndconfig->height;
// TODO: enable visibility support
window->wl.visible = GLFW_TRUE;
// unsupported on Wayland by design
window->focusOnShow = GLFW_FALSE;
if (!createSurface(window))
return GLFW_FALSE; return GLFW_FALSE;
if (ctxconfig->client != GLFW_NO_API) if (ctxconfig->client != GLFW_NO_API)
@ -810,9 +911,7 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window,
} }
} }
if (wndconfig->title) #ifndef WITH_DECORATION
window->wl.title = _glfw_strdup(wndconfig->title);
if (wndconfig->visible) if (wndconfig->visible)
{ {
if (!createXdgSurface(window)) if (!createXdgSurface(window))
@ -826,6 +925,17 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window,
window->wl.xdg.toplevel = NULL; window->wl.xdg.toplevel = NULL;
window->wl.visible = GLFW_FALSE; window->wl.visible = GLFW_FALSE;
} }
#else
if (!createSurfaceDecoration(window))
return GLFW_FALSE;
#endif
window->wl.scale = 1;
_glfwPlatformSetWindowTitle(window, wndconfig->title);
if (window->monitor)
setFullscreen(window, window->monitor, window->videoMode.refreshRate);
window->wl.currentCursor = NULL; window->wl.currentCursor = NULL;
@ -833,6 +943,8 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window,
window->wl.monitorsCount = 0; window->wl.monitorsCount = 0;
window->wl.monitorsSize = 1; window->wl.monitorsSize = 1;
wl_display_roundtrip(_glfw.wl.display);
return GLFW_TRUE; return GLFW_TRUE;
} }
@ -856,20 +968,25 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window)
window->context.destroy(window); window->context.destroy(window);
destroyDecorations(window); destroyDecorations(window);
#ifdef WITH_DECORATION
libdecor_frame_unref(window->wl.decoration_frame);
#else
if (window->wl.xdg.decoration) if (window->wl.xdg.decoration)
zxdg_toplevel_decoration_v1_destroy(window->wl.xdg.decoration); zxdg_toplevel_decoration_v1_destroy(window->wl.xdg.decoration);
if (window->wl.decorations.buffer) if (window->wl.decorations.buffer)
wl_buffer_destroy(window->wl.decorations.buffer); wl_buffer_destroy(window->wl.decorations.buffer);
#endif
if (window->wl.native) if (window->wl.native)
wl_egl_window_destroy(window->wl.native); wl_egl_window_destroy(window->wl.native);
#ifndef WITH_DECORATION
if (window->wl.xdg.toplevel) if (window->wl.xdg.toplevel)
xdg_toplevel_destroy(window->wl.xdg.toplevel); xdg_toplevel_destroy(window->wl.xdg.toplevel);
if (window->wl.xdg.surface) if (window->wl.xdg.surface)
xdg_surface_destroy(window->wl.xdg.surface); xdg_surface_destroy(window->wl.xdg.surface);
#endif
if (window->wl.surface) if (window->wl.surface)
wl_surface_destroy(window->wl.surface); wl_surface_destroy(window->wl.surface);
@ -883,15 +1000,22 @@ void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title)
if (window->wl.title) if (window->wl.title)
free(window->wl.title); free(window->wl.title);
window->wl.title = _glfw_strdup(title); window->wl.title = _glfw_strdup(title);
if (window->wl.xdg.toplevel)
xdg_toplevel_set_title(window->wl.xdg.toplevel, title); #ifdef WITH_DECORATION
if (window->wl.decoration_frame) {
libdecor_frame_set_title(window->wl.decoration_frame, window->wl.title);
libdecor_frame_set_app_id(window->wl.decoration_frame, window->wl.title);
}
#else
xdg_toplevel_set_title(window->wl.xdg.toplevel, title);
#endif
} }
void _glfwPlatformSetWindowIcon(_GLFWwindow* window, void _glfwPlatformSetWindowIcon(_GLFWwindow* window,
int count, const GLFWimage* images) int count, const GLFWimage* images)
{ {
_glfwInputError(GLFW_FEATURE_UNAVAILABLE, // _glfwInputError(GLFW_FEATURE_UNAVAILABLE,
"Wayland: The platform does not support setting the window icon"); // "Wayland: The platform does not support setting the window icon");
} }
void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos) void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos)
@ -930,16 +1054,23 @@ void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window,
int minwidth, int minheight, int minwidth, int minheight,
int maxwidth, int maxheight) int maxwidth, int maxheight)
{ {
if (minwidth == GLFW_DONT_CARE || minheight == GLFW_DONT_CARE)
minwidth = minheight = 0;
if (maxwidth == GLFW_DONT_CARE || maxheight == GLFW_DONT_CARE)
maxwidth = maxheight = 0;
#ifdef WITH_DECORATION
libdecor_frame_set_min_content_size(window->wl.decoration_frame,
minwidth, minheight);
libdecor_frame_set_max_content_size(window->wl.decoration_frame,
maxwidth, maxheight);
#else
if (window->wl.xdg.toplevel) if (window->wl.xdg.toplevel)
{ {
if (minwidth == GLFW_DONT_CARE || minheight == GLFW_DONT_CARE)
minwidth = minheight = 0;
if (maxwidth == GLFW_DONT_CARE || maxheight == GLFW_DONT_CARE)
maxwidth = maxheight = 0;
xdg_toplevel_set_min_size(window->wl.xdg.toplevel, minwidth, minheight); xdg_toplevel_set_min_size(window->wl.xdg.toplevel, minwidth, minheight);
xdg_toplevel_set_max_size(window->wl.xdg.toplevel, maxwidth, maxheight); xdg_toplevel_set_max_size(window->wl.xdg.toplevel, maxwidth, maxheight);
wl_surface_commit(window->wl.surface);
} }
#endif
wl_surface_commit(window->wl.surface);
} }
void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window,
@ -965,6 +1096,7 @@ void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window,
int* left, int* top, int* left, int* top,
int* right, int* bottom) int* right, int* bottom)
{ {
#ifndef WITH_DECORATION
if (window->decorated && !window->monitor && !window->wl.decorations.serverSide) if (window->decorated && !window->monitor && !window->wl.decorations.serverSide)
{ {
if (top) if (top)
@ -976,6 +1108,7 @@ void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window,
if (bottom) if (bottom)
*bottom = _GLFW_DECORATION_WIDTH; *bottom = _GLFW_DECORATION_WIDTH;
} }
#endif
} }
void _glfwPlatformGetWindowContentScale(_GLFWwindow* window, void _glfwPlatformGetWindowContentScale(_GLFWwindow* window,
@ -989,31 +1122,37 @@ void _glfwPlatformGetWindowContentScale(_GLFWwindow* window,
void _glfwPlatformIconifyWindow(_GLFWwindow* window) void _glfwPlatformIconifyWindow(_GLFWwindow* window)
{ {
if (window->wl.xdg.toplevel) #ifdef WITH_DECORATION
xdg_toplevel_set_minimized(window->wl.xdg.toplevel); libdecor_frame_set_minimized(window->wl.decoration_frame);
#else
xdg_toplevel_set_minimized(window->wl.xdg.toplevel);
#endif
} }
void _glfwPlatformRestoreWindow(_GLFWwindow* window) void _glfwPlatformRestoreWindow(_GLFWwindow* window)
{ {
if (window->wl.xdg.toplevel) #ifdef WITH_DECORATION
{ libdecor_frame_unset_fullscreen(window->wl.decoration_frame);
if (window->monitor) libdecor_frame_unset_maximized(window->wl.decoration_frame);
xdg_toplevel_unset_fullscreen(window->wl.xdg.toplevel); #else
if (window->wl.maximized) if (window->monitor)
xdg_toplevel_unset_maximized(window->wl.xdg.toplevel); xdg_toplevel_unset_fullscreen(window->wl.xdg.toplevel);
// There is no way to unset minimized, or even to know if we are if (window->wl.maximized)
// minimized, so there is nothing to do in this case. xdg_toplevel_unset_maximized(window->wl.xdg.toplevel);
} // There is no way to unset minimized, or even to know if we are
// minimized, so there is nothing to do in this case.
#endif
_glfwInputWindowMonitor(window, NULL); _glfwInputWindowMonitor(window, NULL);
window->wl.maximized = GLFW_FALSE; window->wl.maximized = GLFW_FALSE;
} }
void _glfwPlatformMaximizeWindow(_GLFWwindow* window) void _glfwPlatformMaximizeWindow(_GLFWwindow* window)
{ {
if (window->wl.xdg.toplevel) #ifdef WITH_DECORATION
{ libdecor_frame_set_maximized(window->wl.decoration_frame);
xdg_toplevel_set_maximized(window->wl.xdg.toplevel); #else
} xdg_toplevel_set_maximized(window->wl.xdg.toplevel);
#endif
window->wl.maximized = GLFW_TRUE; window->wl.maximized = GLFW_TRUE;
} }
@ -1021,13 +1160,18 @@ void _glfwPlatformShowWindow(_GLFWwindow* window)
{ {
if (!window->wl.visible) if (!window->wl.visible)
{ {
createXdgSurface(window);
window->wl.visible = GLFW_TRUE; window->wl.visible = GLFW_TRUE;
#ifndef WITH_DECORATION
createXdgSurface(window);
#else
// TODO: enable visibility support
#endif
} }
} }
void _glfwPlatformHideWindow(_GLFWwindow* window) void _glfwPlatformHideWindow(_GLFWwindow* window)
{ {
#ifndef WITH_DECORATION
if (window->wl.xdg.toplevel) if (window->wl.xdg.toplevel)
{ {
xdg_toplevel_destroy(window->wl.xdg.toplevel); xdg_toplevel_destroy(window->wl.xdg.toplevel);
@ -1035,6 +1179,9 @@ void _glfwPlatformHideWindow(_GLFWwindow* window)
window->wl.xdg.toplevel = NULL; window->wl.xdg.toplevel = NULL;
window->wl.xdg.surface = NULL; window->wl.xdg.surface = NULL;
} }
#else
// TODO: enable visibility support
#endif
window->wl.visible = GLFW_FALSE; window->wl.visible = GLFW_FALSE;
} }
@ -1047,8 +1194,8 @@ void _glfwPlatformRequestWindowAttention(_GLFWwindow* window)
void _glfwPlatformFocusWindow(_GLFWwindow* window) void _glfwPlatformFocusWindow(_GLFWwindow* window)
{ {
_glfwInputError(GLFW_FEATURE_UNAVAILABLE, // _glfwInputError(GLFW_FEATURE_UNAVAILABLE,
"Wayland: The platform does not support setting the input focus"); // "Wayland: The platform does not support setting the input focus");
} }
void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, void _glfwPlatformSetWindowMonitor(_GLFWwindow* window,
@ -1063,11 +1210,14 @@ void _glfwPlatformSetWindowMonitor(_GLFWwindow* window,
} }
else else
{ {
if (window->wl.xdg.toplevel) #ifdef WITH_DECORATION
xdg_toplevel_unset_fullscreen(window->wl.xdg.toplevel); libdecor_frame_unset_fullscreen(window->wl.decoration_frame);
#else
xdg_toplevel_unset_fullscreen(window->wl.xdg.toplevel);
setIdleInhibitor(window, GLFW_FALSE); setIdleInhibitor(window, GLFW_FALSE);
if (!_glfw.wl.decorationManager) if (!_glfw.wl.decorationManager)
createDecorations(window); createDecorations(window);
#endif
} }
_glfwInputWindowMonitor(window, monitor); _glfwInputWindowMonitor(window, monitor);
} }
@ -1440,8 +1590,9 @@ static void lockPointer(_GLFWwindow* window)
window->wl.pointerLock.relativePointer = relativePointer; window->wl.pointerLock.relativePointer = relativePointer;
window->wl.pointerLock.lockedPointer = lockedPointer; window->wl.pointerLock.lockedPointer = lockedPointer;
wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.serial, wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.serial, NULL, 0, 0);
NULL, 0, 0); wl_surface_attach(_glfw.wl.cursorSurface, NULL, 0, 0);
wl_surface_commit(_glfw.wl.cursorSurface);
} }
static GLFWbool isPointerLocked(_GLFWwindow* window) static GLFWbool isPointerLocked(_GLFWwindow* window)
@ -1459,10 +1610,14 @@ void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor)
window->wl.currentCursor = cursor; window->wl.currentCursor = cursor;
if (window != _glfw.wl.pointerFocus) return;
#ifndef WITH_DECORATION
// If we're not in the correct window just save the 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 // the next time the pointer enters the window the cursor will change
if (window != _glfw.wl.pointerFocus || window->wl.decorations.focus != mainWindow) if (window->wl.decorations.focus != mainWindow)
return; return;
#endif
// Unlock possible pointer lock if no longer disabled. // Unlock possible pointer lock if no longer disabled.
if (window->cursorMode != GLFW_CURSOR_DISABLED && isPointerLocked(window)) if (window->cursorMode != GLFW_CURSOR_DISABLED && isPointerLocked(window))