Merge branch 'glfw:master' into drag-window-dev

This commit is contained in:
Naveen Karuthedath 2023-03-28 22:00:05 +05:30 committed by GitHub
commit 36987271f2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 811 additions and 188 deletions

View File

@ -3,6 +3,7 @@ on:
pull_request: pull_request:
push: push:
branches: [ ci, master, latest, 3.3-stable ] branches: [ ci, master, latest, 3.3-stable ]
workflow_dispatch:
permissions: permissions:
statuses: write statuses: write
contents: read contents: read
@ -15,7 +16,7 @@ jobs:
CC: clang CC: clang
CFLAGS: -Werror CFLAGS: -Werror
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
- name: Install dependencies - name: Install dependencies
run: | run: |
sudo apt update sudo apt update
@ -38,7 +39,7 @@ jobs:
CC: clang CC: clang
CFLAGS: -Werror CFLAGS: -Werror
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
- name: Install dependencies - name: Install dependencies
run: | run: |
sudo apt update sudo apt update
@ -61,7 +62,7 @@ jobs:
CFLAGS: -Werror CFLAGS: -Werror
MACOSX_DEPLOYMENT_TARGET: 10.8 MACOSX_DEPLOYMENT_TARGET: 10.8
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
- name: Configure static library - name: Configure static library
run: cmake -S . -B build-static run: cmake -S . -B build-static
@ -79,7 +80,7 @@ jobs:
env: env:
CFLAGS: /WX CFLAGS: /WX
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
- name: Configure static library - name: Configure static library
run: cmake -S . -B build-static -G "Visual Studio 17 2022" run: cmake -S . -B build-static -G "Visual Studio 17 2022"

View File

@ -2,12 +2,6 @@ cmake_minimum_required(VERSION 3.4...3.20 FATAL_ERROR)
project(GLFW VERSION 3.4.0 LANGUAGES C) project(GLFW VERSION 3.4.0 LANGUAGES C)
set(CMAKE_LEGACY_CYGWIN_WIN32 OFF)
if (POLICY CMP0054)
cmake_policy(SET CMP0054 NEW)
endif()
if (POLICY CMP0069) if (POLICY CMP0069)
cmake_policy(SET CMP0069 NEW) cmake_policy(SET CMP0069 NEW)
endif() endif()
@ -18,9 +12,7 @@ endif()
set_property(GLOBAL PROPERTY USE_FOLDERS ON) set_property(GLOBAL PROPERTY USE_FOLDERS ON)
if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) string(COMPARE EQUAL ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_SOURCE_DIR} GLFW_STANDALONE)
set(GLFW_STANDALONE TRUE)
endif()
option(BUILD_SHARED_LIBS "Build shared libraries" OFF) option(BUILD_SHARED_LIBS "Build shared libraries" OFF)
option(GLFW_BUILD_EXAMPLES "Build the GLFW example programs" ${GLFW_STANDALONE}) option(GLFW_BUILD_EXAMPLES "Build the GLFW example programs" ${GLFW_STANDALONE})

View File

@ -8,6 +8,7 @@ video tutorials.
- Bobyshev Alexander - Bobyshev Alexander
- Laurent Aphecetche - Laurent Aphecetche
- Matt Arsenault - Matt Arsenault
- Takuro Ashie
- ashishgamedev - ashishgamedev
- David Avedissian - David Avedissian
- Luca Bacci - Luca Bacci
@ -187,6 +188,7 @@ video tutorials.
- pthom - pthom
- Martin Pulec - Martin Pulec
- Guillaume Racicot - Guillaume Racicot
- Juan Ramos
- Christian Rauch - Christian Rauch
- Philip Rideout - Philip Rideout
- Eddie Ringle - Eddie Ringle
@ -199,6 +201,7 @@ video tutorials.
- Aleksey Rybalkin - Aleksey Rybalkin
- Mikko Rytkönen - Mikko Rytkönen
- Riku Salminen - Riku Salminen
- Yoshinori Sano
- Brandon Schaefer - Brandon Schaefer
- Sebastian Schuberth - Sebastian Schuberth
- Christian Sdunek - Christian Sdunek

View File

@ -312,6 +312,7 @@ information on what to include when reporting a bug.
- [X11] Bugfix: The OSMesa libray was not unloaded on termination - [X11] Bugfix: The OSMesa libray was not unloaded on termination
- [X11] Bugfix: A malformed response during selection transfer could cause a segfault - [X11] Bugfix: A malformed response during selection transfer could cause a segfault
- [X11] Bugfix: Some calls would reset Xlib to the default error handler (#2108) - [X11] Bugfix: Some calls would reset Xlib to the default error handler (#2108)
- [Wayland] Added improved fallback window decorations via libdecor (#1639,#1693)
- [Wayland] Added dynamic loading of all Wayland libraries - [Wayland] Added dynamic loading of all Wayland libraries
- [Wayland] Added support for key names via xkbcommon - [Wayland] Added support for key names via xkbcommon
- [Wayland] Added support for file path drop events (#2040) - [Wayland] Added support for file path drop events (#2040)

View File

@ -128,6 +128,14 @@ wayland-protocols 1.6, and mandatory at build time. If the running compositor
does not support this protocol, the screensaver may start even for full screen does not support this protocol, the screensaver may start even for full screen
windows. windows.
GLFW uses the [libdecor library](https://gitlab.freedesktop.org/libdecor/libdecor)
for window decorations, where available. This in turn provides good quality
client-side decorations (drawn by the application) on desktop systems that do
not support server-side decorations (drawn by the window manager). On systems
that do not provide either libdecor or xdg-decoration, very basic window
decorations are provided. These do not include the window title or any caption
buttons.
GLFW uses the [xdg-decoration GLFW uses the [xdg-decoration
protocol](https://cgit.freedesktop.org/wayland/wayland-protocols/tree/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml) protocol](https://cgit.freedesktop.org/wayland/wayland-protocols/tree/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml)
to request decorations to be drawn around its windows. This protocol is part to request decorations to be drawn around its windows. This protocol is part

View File

@ -144,6 +144,15 @@ the `VK_KHR_xlib_surface` extension. Possible values are `GLFW_TRUE` and
`GLFW_FALSE`. This is ignored on other platforms. `GLFW_FALSE`. This is ignored on other platforms.
@subsubsection init_hints_wayland Wayland specific init hints
@anchor GLFW_WAYLAND_LIBDECOR_hint
__GLFW_WAYLAND_LIBDECOR__ specifies whether to use
[libdecor](https://gitlab.freedesktop.org/libdecor/libdecor) for window
decorations where available. Possible values are `GLFW_WAYLAND_PREFER_LIBDECOR`
and `GLFW_WAYLAND_DISABLE_LIBDECOR`. This is ignored on other platforms.
@subsubsection init_hints_values Supported and default values @subsubsection init_hints_values Supported and default values
Initialization hint | Default value | Supported values Initialization hint | Default value | Supported values
@ -154,6 +163,7 @@ Initialization hint | Default value | Supported v
@ref GLFW_COCOA_CHDIR_RESOURCES | `GLFW_TRUE` | `GLFW_TRUE` or `GLFW_FALSE` @ref GLFW_COCOA_CHDIR_RESOURCES | `GLFW_TRUE` | `GLFW_TRUE` or `GLFW_FALSE`
@ref GLFW_COCOA_MENUBAR | `GLFW_TRUE` | `GLFW_TRUE` or `GLFW_FALSE` @ref GLFW_COCOA_MENUBAR | `GLFW_TRUE` | `GLFW_TRUE` or `GLFW_FALSE`
@ref GLFW_X11_XCB_VULKAN_SURFACE | `GLFW_TRUE` | `GLFW_TRUE` or `GLFW_FALSE` @ref GLFW_X11_XCB_VULKAN_SURFACE | `GLFW_TRUE` | `GLFW_TRUE` or `GLFW_FALSE`
@ref GLFW_WAYLAND_LIBDECOR | `GLFW_WAYLAND_PREFER_LIBDECOR` | `GLFW_WAYLAND_PREFER_LIBDECOR` or `GLFW_WAYLAND_DISABLE_LIBDECOR`
@subsection platform Runtime platform selection @subsection platform Runtime platform selection

View File

@ -43,6 +43,16 @@ to whatever window is behind it. This can also be changed after window
creation with the matching [window attribute](@ref GLFW_MOUSE_PASSTHROUGH_attrib). creation with the matching [window attribute](@ref GLFW_MOUSE_PASSTHROUGH_attrib).
@subsubsection wayland_libdecor_34 Wayland libdecor decorations
GLFW now supports improved fallback window decorations via
[libdecor](https://gitlab.freedesktop.org/libdecor/libdecor).
Support for libdecor can be toggled before GLFW is initialized with the
[GLFW_WAYLAND_LIBDECOR](@ref GLFW_WAYLAND_LIBDECOR_hint) init hint. It is
enabled by default.
@subsubsection wayland_app_id_34 Wayland app_id specification @subsubsection wayland_app_id_34 Wayland app_id specification
GLFW now supports specifying the app_id for a Wayland window using the GLFW now supports specifying the app_id for a Wayland window using the
@ -267,6 +277,9 @@ then GLFW will fail to initialize.
- @ref GLFW_POSITION_X - @ref GLFW_POSITION_X
- @ref GLFW_POSITION_Y - @ref GLFW_POSITION_Y
- @ref GLFW_ANY_POSITION - @ref GLFW_ANY_POSITION
- @ref GLFW_WAYLAND_LIBDECOR
- @ref GLFW_WAYLAND_PREFER_LIBDECOR
- @ref GLFW_WAYLAND_DISABLE_LIBDECOR
@section news_archive Release notes for earlier versions @section news_archive Release notes for earlier versions

View File

@ -1164,6 +1164,9 @@ extern "C" {
#define GLFW_ANGLE_PLATFORM_TYPE_VULKAN 0x00037007 #define GLFW_ANGLE_PLATFORM_TYPE_VULKAN 0x00037007
#define GLFW_ANGLE_PLATFORM_TYPE_METAL 0x00037008 #define GLFW_ANGLE_PLATFORM_TYPE_METAL 0x00037008
#define GLFW_WAYLAND_PREFER_LIBDECOR 0x00038001
#define GLFW_WAYLAND_DISABLE_LIBDECOR 0x00038002
#define GLFW_ANY_POSITION 0x80000000 #define GLFW_ANY_POSITION 0x80000000
/*! @defgroup shapes Standard cursor shapes /*! @defgroup shapes Standard cursor shapes
@ -1307,6 +1310,11 @@ extern "C" {
* X11 specific [init hint](@ref GLFW_X11_XCB_VULKAN_SURFACE_hint). * X11 specific [init hint](@ref GLFW_X11_XCB_VULKAN_SURFACE_hint).
*/ */
#define GLFW_X11_XCB_VULKAN_SURFACE 0x00052001 #define GLFW_X11_XCB_VULKAN_SURFACE 0x00052001
/*! @brief Wayland specific init hint.
*
* Wayland specific [init hint](@ref GLFW_WAYLAND_LIBDECOR_hint).
*/
#define GLFW_WAYLAND_LIBDECOR 0x00053001
/*! @} */ /*! @} */
/*! @addtogroup init /*! @addtogroup init

View File

@ -62,6 +62,9 @@ static _GLFWinitconfig _glfwInitHints =
{ {
GLFW_TRUE, // X11 XCB Vulkan surface GLFW_TRUE, // X11 XCB Vulkan surface
}, },
{
GLFW_WAYLAND_PREFER_LIBDECOR // Wayland libdecor mode
},
}; };
// The allocation function used when no custom allocator is set // The allocation function used when no custom allocator is set
@ -479,6 +482,9 @@ GLFWAPI void glfwInitHint(int hint, int value)
case GLFW_X11_XCB_VULKAN_SURFACE: case GLFW_X11_XCB_VULKAN_SURFACE:
_glfwInitHints.x11.xcbVulkanSurface = value; _glfwInitHints.x11.xcbVulkanSurface = value;
return; return;
case GLFW_WAYLAND_LIBDECOR:
_glfwInitHints.wl.libdecorMode = value;
return;
} }
_glfwInputError(GLFW_INVALID_ENUM, _glfwInputError(GLFW_INVALID_ENUM,

View File

@ -379,6 +379,9 @@ struct _GLFWinitconfig
struct { struct {
GLFWbool xcbVulkanSurface; GLFWbool xcbVulkanSurface;
} x11; } x11;
struct {
int libdecorMode;
} wl;
}; };
// Window configuration // Window configuration

View File

@ -384,7 +384,7 @@ static GLFWbool createHelperWindow(void)
if (!_glfw.win32.helperWindowClass) if (!_glfw.win32.helperWindowClass)
{ {
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR, _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
"WIn32: Failed to register helper window class"); "Win32: Failed to register helper window class");
return GLFW_FALSE; return GLFW_FALSE;
} }

View File

@ -102,10 +102,9 @@ static void registryHandleGlobal(void* userData,
{ {
if (strcmp(interface, "wl_compositor") == 0) if (strcmp(interface, "wl_compositor") == 0)
{ {
_glfw.wl.compositorVersion = _glfw_min(3, version);
_glfw.wl.compositor = _glfw.wl.compositor =
wl_registry_bind(registry, name, &wl_compositor_interface, wl_registry_bind(registry, name, &wl_compositor_interface,
_glfw.wl.compositorVersion); _glfw_min(3, version));
} }
else if (strcmp(interface, "wl_subcompositor") == 0) else if (strcmp(interface, "wl_subcompositor") == 0)
{ {
@ -125,10 +124,9 @@ static void registryHandleGlobal(void* userData,
{ {
if (!_glfw.wl.seat) if (!_glfw.wl.seat)
{ {
_glfw.wl.seatVersion = _glfw_min(4, version);
_glfw.wl.seat = _glfw.wl.seat =
wl_registry_bind(registry, name, &wl_seat_interface, wl_registry_bind(registry, name, &wl_seat_interface,
_glfw.wl.seatVersion); _glfw_min(4, version));
_glfwAddSeatListenerWayland(_glfw.wl.seat); _glfwAddSeatListenerWayland(_glfw.wl.seat);
} }
} }
@ -204,6 +202,20 @@ static const struct wl_registry_listener registryListener =
registryHandleGlobalRemove registryHandleGlobalRemove
}; };
void libdecorHandleError(struct libdecor* context,
enum libdecor_error error,
const char* message)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: libdecor error %u: %s",
error, message);
}
static const struct libdecor_interface libdecorInterface =
{
libdecorHandleError
};
// Create key code translation tables // Create key code translation tables
// //
static void createKeyTables(void) static void createKeyTables(void)
@ -339,7 +351,7 @@ static void createKeyTables(void)
static GLFWbool loadCursorTheme(void) static GLFWbool loadCursorTheme(void)
{ {
int cursorSize = 32; int cursorSize = 16;
const char* sizeString = getenv("XCURSOR_SIZE"); const char* sizeString = getenv("XCURSOR_SIZE");
if (sizeString) if (sizeString)
@ -394,7 +406,7 @@ GLFWbool _glfwConnectWayland(int platformID, _GLFWplatform* platform)
_glfwGetKeyScancodeWayland, _glfwGetKeyScancodeWayland,
_glfwSetClipboardStringWayland, _glfwSetClipboardStringWayland,
_glfwGetClipboardStringWayland, _glfwGetClipboardStringWayland,
#if defined(_GLFW_LINUX_JOYSTICK) #if defined(GLFW_BUILD_LINUX_JOYSTICK)
_glfwInitJoysticksLinux, _glfwInitJoysticksLinux,
_glfwTerminateJoysticksLinux, _glfwTerminateJoysticksLinux,
_glfwPollJoystickLinux, _glfwPollJoystickLinux,
@ -510,6 +522,8 @@ int _glfwInitWayland(void)
_glfw.wl.keyRepeatTimerfd = -1; _glfw.wl.keyRepeatTimerfd = -1;
_glfw.wl.cursorTimerfd = -1; _glfw.wl.cursorTimerfd = -1;
_glfw.wl.tag = glfwGetVersionString();
_glfw.wl.client.display_flush = (PFN_wl_display_flush) _glfw.wl.client.display_flush = (PFN_wl_display_flush)
_glfwPlatformGetModuleSymbol(_glfw.wl.client.handle, "wl_display_flush"); _glfwPlatformGetModuleSymbol(_glfw.wl.client.handle, "wl_display_flush");
_glfw.wl.client.display_cancel_read = (PFN_wl_display_cancel_read) _glfw.wl.client.display_cancel_read = (PFN_wl_display_cancel_read)
@ -540,6 +554,10 @@ int _glfwInitWayland(void)
_glfwPlatformGetModuleSymbol(_glfw.wl.client.handle, "wl_proxy_get_user_data"); _glfwPlatformGetModuleSymbol(_glfw.wl.client.handle, "wl_proxy_get_user_data");
_glfw.wl.client.proxy_set_user_data = (PFN_wl_proxy_set_user_data) _glfw.wl.client.proxy_set_user_data = (PFN_wl_proxy_set_user_data)
_glfwPlatformGetModuleSymbol(_glfw.wl.client.handle, "wl_proxy_set_user_data"); _glfwPlatformGetModuleSymbol(_glfw.wl.client.handle, "wl_proxy_set_user_data");
_glfw.wl.client.proxy_get_tag = (PFN_wl_proxy_get_tag)
_glfwPlatformGetModuleSymbol(_glfw.wl.client.handle, "wl_proxy_get_tag");
_glfw.wl.client.proxy_set_tag = (PFN_wl_proxy_set_tag)
_glfwPlatformGetModuleSymbol(_glfw.wl.client.handle, "wl_proxy_set_tag");
_glfw.wl.client.proxy_get_version = (PFN_wl_proxy_get_version) _glfw.wl.client.proxy_get_version = (PFN_wl_proxy_get_version)
_glfwPlatformGetModuleSymbol(_glfw.wl.client.handle, "wl_proxy_get_version"); _glfwPlatformGetModuleSymbol(_glfw.wl.client.handle, "wl_proxy_get_version");
_glfw.wl.client.proxy_marshal_flags = (PFN_wl_proxy_marshal_flags) _glfw.wl.client.proxy_marshal_flags = (PFN_wl_proxy_marshal_flags)
@ -559,7 +577,9 @@ int _glfwInitWayland(void)
!_glfw.wl.client.proxy_marshal_constructor || !_glfw.wl.client.proxy_marshal_constructor ||
!_glfw.wl.client.proxy_marshal_constructor_versioned || !_glfw.wl.client.proxy_marshal_constructor_versioned ||
!_glfw.wl.client.proxy_get_user_data || !_glfw.wl.client.proxy_get_user_data ||
!_glfw.wl.client.proxy_set_user_data) !_glfw.wl.client.proxy_set_user_data ||
!_glfw.wl.client.proxy_get_tag ||
!_glfw.wl.client.proxy_set_tag)
{ {
_glfwInputError(GLFW_PLATFORM_ERROR, _glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: Failed to load libwayland-client entry point"); "Wayland: Failed to load libwayland-client entry point");
@ -647,6 +667,93 @@ int _glfwInitWayland(void)
_glfw.wl.xkb.compose_state_get_one_sym = (PFN_xkb_compose_state_get_one_sym) _glfw.wl.xkb.compose_state_get_one_sym = (PFN_xkb_compose_state_get_one_sym)
_glfwPlatformGetModuleSymbol(_glfw.wl.xkb.handle, "xkb_compose_state_get_one_sym"); _glfwPlatformGetModuleSymbol(_glfw.wl.xkb.handle, "xkb_compose_state_get_one_sym");
if (_glfw.hints.init.wl.libdecorMode == GLFW_WAYLAND_PREFER_LIBDECOR)
_glfw.wl.libdecor.handle = _glfwPlatformLoadModule("libdecor-0.so.0");
if (_glfw.wl.libdecor.handle)
{
_glfw.wl.libdecor.libdecor_new_ = (PFN_libdecor_new)
_glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_new");
_glfw.wl.libdecor.libdecor_unref_ = (PFN_libdecor_unref)
_glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_unref");
_glfw.wl.libdecor.libdecor_get_fd_ = (PFN_libdecor_get_fd)
_glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_get_fd");
_glfw.wl.libdecor.libdecor_dispatch_ = (PFN_libdecor_dispatch)
_glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_dispatch");
_glfw.wl.libdecor.libdecor_decorate_ = (PFN_libdecor_decorate)
_glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_decorate");
_glfw.wl.libdecor.libdecor_frame_unref_ = (PFN_libdecor_frame_unref)
_glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_frame_unref");
_glfw.wl.libdecor.libdecor_frame_set_app_id_ = (PFN_libdecor_frame_set_app_id)
_glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_frame_set_app_id");
_glfw.wl.libdecor.libdecor_frame_set_title_ = (PFN_libdecor_frame_set_title)
_glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_frame_set_title");
_glfw.wl.libdecor.libdecor_frame_set_minimized_ = (PFN_libdecor_frame_set_minimized)
_glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_frame_set_minimized");
_glfw.wl.libdecor.libdecor_frame_set_fullscreen_ = (PFN_libdecor_frame_set_fullscreen)
_glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_frame_set_fullscreen");
_glfw.wl.libdecor.libdecor_frame_unset_fullscreen_ = (PFN_libdecor_frame_unset_fullscreen)
_glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_frame_unset_fullscreen");
_glfw.wl.libdecor.libdecor_frame_map_ = (PFN_libdecor_frame_map)
_glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_frame_map");
_glfw.wl.libdecor.libdecor_frame_commit_ = (PFN_libdecor_frame_commit)
_glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_frame_commit");
_glfw.wl.libdecor.libdecor_frame_set_min_content_size_ = (PFN_libdecor_frame_set_min_content_size)
_glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_frame_set_min_content_size");
_glfw.wl.libdecor.libdecor_frame_set_max_content_size_ = (PFN_libdecor_frame_set_max_content_size)
_glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_frame_set_max_content_size");
_glfw.wl.libdecor.libdecor_frame_set_maximized_ = (PFN_libdecor_frame_set_maximized)
_glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_frame_set_maximized");
_glfw.wl.libdecor.libdecor_frame_unset_maximized_ = (PFN_libdecor_frame_unset_maximized)
_glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_frame_unset_maximized");
_glfw.wl.libdecor.libdecor_frame_set_capabilities_ = (PFN_libdecor_frame_set_capabilities)
_glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_frame_set_capabilities");
_glfw.wl.libdecor.libdecor_frame_unset_capabilities_ = (PFN_libdecor_frame_unset_capabilities)
_glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_frame_unset_capabilities");
_glfw.wl.libdecor.libdecor_frame_set_visibility_ = (PFN_libdecor_frame_set_visibility)
_glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_frame_set_visibility");
_glfw.wl.libdecor.libdecor_frame_get_xdg_toplevel_ = (PFN_libdecor_frame_get_xdg_toplevel)
_glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_frame_get_xdg_toplevel");
_glfw.wl.libdecor.libdecor_configuration_get_content_size_ = (PFN_libdecor_configuration_get_content_size)
_glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_configuration_get_content_size");
_glfw.wl.libdecor.libdecor_configuration_get_window_state_ = (PFN_libdecor_configuration_get_window_state)
_glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_configuration_get_window_state");
_glfw.wl.libdecor.libdecor_state_new_ = (PFN_libdecor_state_new)
_glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_state_new");
_glfw.wl.libdecor.libdecor_state_free_ = (PFN_libdecor_state_free)
_glfwPlatformGetModuleSymbol(_glfw.wl.libdecor.handle, "libdecor_state_free");
if (!_glfw.wl.libdecor.libdecor_new_ ||
!_glfw.wl.libdecor.libdecor_unref_ ||
!_glfw.wl.libdecor.libdecor_get_fd_ ||
!_glfw.wl.libdecor.libdecor_dispatch_ ||
!_glfw.wl.libdecor.libdecor_decorate_ ||
!_glfw.wl.libdecor.libdecor_frame_unref_ ||
!_glfw.wl.libdecor.libdecor_frame_set_app_id_ ||
!_glfw.wl.libdecor.libdecor_frame_set_title_ ||
!_glfw.wl.libdecor.libdecor_frame_set_minimized_ ||
!_glfw.wl.libdecor.libdecor_frame_set_fullscreen_ ||
!_glfw.wl.libdecor.libdecor_frame_unset_fullscreen_ ||
!_glfw.wl.libdecor.libdecor_frame_map_ ||
!_glfw.wl.libdecor.libdecor_frame_commit_ ||
!_glfw.wl.libdecor.libdecor_frame_set_min_content_size_ ||
!_glfw.wl.libdecor.libdecor_frame_set_max_content_size_ ||
!_glfw.wl.libdecor.libdecor_frame_set_maximized_ ||
!_glfw.wl.libdecor.libdecor_frame_unset_maximized_ ||
!_glfw.wl.libdecor.libdecor_frame_set_capabilities_ ||
!_glfw.wl.libdecor.libdecor_frame_unset_capabilities_ ||
!_glfw.wl.libdecor.libdecor_frame_set_visibility_ ||
!_glfw.wl.libdecor.libdecor_frame_get_xdg_toplevel_ ||
!_glfw.wl.libdecor.libdecor_configuration_get_content_size_ ||
!_glfw.wl.libdecor.libdecor_configuration_get_window_state_ ||
!_glfw.wl.libdecor.libdecor_state_new_ ||
!_glfw.wl.libdecor.libdecor_state_free_)
{
_glfwPlatformFreeModule(_glfw.wl.libdecor.handle);
memset(&_glfw.wl.libdecor, 0, sizeof(_glfw.wl.libdecor));
}
}
_glfw.wl.registry = wl_display_get_registry(_glfw.wl.display); _glfw.wl.registry = wl_display_get_registry(_glfw.wl.display);
wl_registry_add_listener(_glfw.wl.registry, &registryListener, NULL); wl_registry_add_listener(_glfw.wl.registry, &registryListener, NULL);
@ -666,8 +773,17 @@ int _glfwInitWayland(void)
// Sync so we got all initial output events // Sync so we got all initial output events
wl_display_roundtrip(_glfw.wl.display); wl_display_roundtrip(_glfw.wl.display);
if (_glfw.wl.libdecor.handle)
{
_glfw.wl.libdecor.context = libdecor_new(_glfw.wl.display, &libdecorInterface);
// Allow libdecor to receive its globals before proceeding
if (_glfw.wl.libdecor.context)
libdecor_dispatch(_glfw.wl.libdecor.context, 1);
}
#ifdef WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION #ifdef WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION
if (_glfw.wl.seatVersion >= WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION) if (wl_seat_get_version(_glfw.wl.seat) >= WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION)
{ {
_glfw.wl.keyRepeatTimerfd = _glfw.wl.keyRepeatTimerfd =
timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK); timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK);
@ -707,6 +823,15 @@ void _glfwTerminateWayland(void)
_glfwTerminateEGL(); _glfwTerminateEGL();
_glfwTerminateOSMesa(); _glfwTerminateOSMesa();
if (_glfw.wl.libdecor.context)
libdecor_unref(_glfw.wl.libdecor.context);
if (_glfw.wl.libdecor.handle)
{
_glfwPlatformFreeModule(_glfw.wl.libdecor.handle);
_glfw.wl.libdecor.handle = NULL;
}
if (_glfw.wl.egl.handle) if (_glfw.wl.egl.handle)
{ {
_glfwPlatformFreeModule(_glfw.wl.egl.handle); _glfwPlatformFreeModule(_glfw.wl.egl.handle);

View File

@ -114,14 +114,15 @@ static void outputHandleScale(void* userData,
{ {
struct _GLFWmonitor* monitor = userData; struct _GLFWmonitor* monitor = userData;
monitor->wl.scale = factor; monitor->wl.contentScale = factor;
for (_GLFWwindow* window = _glfw.windowListHead; window; window = window->next) for (_GLFWwindow* window = _glfw.windowListHead; window; window = window->next)
{ {
for (int i = 0; i < window->wl.monitorsCount; i++) for (int i = 0; i < window->wl.scaleCount; i++)
{ {
if (window->wl.monitors[i] == monitor) if (window->wl.scales[i].output == monitor->wl.output)
{ {
window->wl.scales[i].factor = monitor->wl.contentScale;
_glfwUpdateContentScaleWayland(window); _glfwUpdateContentScaleWayland(window);
break; break;
} }
@ -187,10 +188,11 @@ void _glfwAddOutputWayland(uint32_t name, uint32_t version)
// The actual name of this output will be set in the geometry handler // The actual name of this output will be set in the geometry handler
_GLFWmonitor* monitor = _glfwAllocMonitor("", 0, 0); _GLFWmonitor* monitor = _glfwAllocMonitor("", 0, 0);
monitor->wl.scale = 1; monitor->wl.contentScale = 1;
monitor->wl.output = output; monitor->wl.output = output;
monitor->wl.name = name; monitor->wl.name = name;
wl_proxy_set_tag((struct wl_proxy*) output, &_glfw.wl.tag);
wl_output_add_listener(output, &outputListener, monitor); wl_output_add_listener(output, &outputListener, monitor);
} }
@ -217,9 +219,9 @@ void _glfwGetMonitorContentScaleWayland(_GLFWmonitor* monitor,
float* xscale, float* yscale) float* xscale, float* yscale)
{ {
if (xscale) if (xscale)
*xscale = (float) monitor->wl.scale; *xscale = (float) monitor->wl.contentScale;
if (yscale) if (yscale)
*yscale = (float) monitor->wl.scale; *yscale = (float) monitor->wl.contentScale;
} }
void _glfwGetMonitorWorkareaWayland(_GLFWmonitor* monitor, void _glfwGetMonitorWorkareaWayland(_GLFWmonitor* monitor,

View File

@ -28,6 +28,8 @@
#include <xkbcommon/xkbcommon.h> #include <xkbcommon/xkbcommon.h>
#include <xkbcommon/xkbcommon-compose.h> #include <xkbcommon/xkbcommon-compose.h>
#include <stdbool.h>
typedef VkFlags VkWaylandSurfaceCreateFlagsKHR; typedef VkFlags VkWaylandSurfaceCreateFlagsKHR;
typedef struct VkWaylandSurfaceCreateInfoKHR typedef struct VkWaylandSurfaceCreateInfoKHR
@ -61,6 +63,8 @@ typedef struct wl_proxy* (* PFN_wl_proxy_marshal_constructor)(struct wl_proxy*,u
typedef struct wl_proxy* (* PFN_wl_proxy_marshal_constructor_versioned)(struct wl_proxy*,uint32_t,const struct wl_interface*,uint32_t,...); typedef struct wl_proxy* (* PFN_wl_proxy_marshal_constructor_versioned)(struct wl_proxy*,uint32_t,const struct wl_interface*,uint32_t,...);
typedef void* (* PFN_wl_proxy_get_user_data)(struct wl_proxy*); typedef void* (* PFN_wl_proxy_get_user_data)(struct wl_proxy*);
typedef void (* PFN_wl_proxy_set_user_data)(struct wl_proxy*,void*); typedef void (* PFN_wl_proxy_set_user_data)(struct wl_proxy*,void*);
typedef void (* PFN_wl_proxy_set_tag)(struct wl_proxy*,const char*const*);
typedef const char* const* (* PFN_wl_proxy_get_tag)(struct wl_proxy*);
typedef uint32_t (* PFN_wl_proxy_get_version)(struct wl_proxy*); typedef uint32_t (* PFN_wl_proxy_get_version)(struct wl_proxy*);
typedef struct wl_proxy* (* PFN_wl_proxy_marshal_flags)(struct wl_proxy*,uint32_t,const struct wl_interface*,uint32_t,uint32_t,...); typedef struct wl_proxy* (* PFN_wl_proxy_marshal_flags)(struct wl_proxy*,uint32_t,const struct wl_interface*,uint32_t,uint32_t,...);
#define wl_display_flush _glfw.wl.client.display_flush #define wl_display_flush _glfw.wl.client.display_flush
@ -78,10 +82,13 @@ typedef struct wl_proxy* (* PFN_wl_proxy_marshal_flags)(struct wl_proxy*,uint32_
#define wl_proxy_marshal_constructor_versioned _glfw.wl.client.proxy_marshal_constructor_versioned #define wl_proxy_marshal_constructor_versioned _glfw.wl.client.proxy_marshal_constructor_versioned
#define wl_proxy_get_user_data _glfw.wl.client.proxy_get_user_data #define wl_proxy_get_user_data _glfw.wl.client.proxy_get_user_data
#define wl_proxy_set_user_data _glfw.wl.client.proxy_set_user_data #define wl_proxy_set_user_data _glfw.wl.client.proxy_set_user_data
#define wl_proxy_get_tag _glfw.wl.client.proxy_get_tag
#define wl_proxy_set_tag _glfw.wl.client.proxy_set_tag
#define wl_proxy_get_version _glfw.wl.client.proxy_get_version #define wl_proxy_get_version _glfw.wl.client.proxy_get_version
#define wl_proxy_marshal_flags _glfw.wl.client.proxy_marshal_flags #define wl_proxy_marshal_flags _glfw.wl.client.proxy_marshal_flags
struct wl_shm; struct wl_shm;
struct wl_output;
#define wl_display_interface _glfw_wl_display_interface #define wl_display_interface _glfw_wl_display_interface
#define wl_subcompositor_interface _glfw_wl_subcompositor_interface #define wl_subcompositor_interface _glfw_wl_subcompositor_interface
@ -198,13 +205,129 @@ typedef xkb_keysym_t (* PFN_xkb_compose_state_get_one_sym)(struct xkb_compose_st
#define xkb_compose_state_get_status _glfw.wl.xkb.compose_state_get_status #define xkb_compose_state_get_status _glfw.wl.xkb.compose_state_get_status
#define xkb_compose_state_get_one_sym _glfw.wl.xkb.compose_state_get_one_sym #define xkb_compose_state_get_one_sym _glfw.wl.xkb.compose_state_get_one_sym
struct libdecor;
struct libdecor_frame;
struct libdecor_state;
struct libdecor_configuration;
enum libdecor_error
{
LIBDECOR_ERROR_COMPOSITOR_INCOMPATIBLE,
LIBDECOR_ERROR_INVALID_FRAME_CONFIGURATION,
};
enum libdecor_window_state
{
LIBDECOR_WINDOW_STATE_NONE = 0,
LIBDECOR_WINDOW_STATE_ACTIVE = 1,
LIBDECOR_WINDOW_STATE_MAXIMIZED = 2,
LIBDECOR_WINDOW_STATE_FULLSCREEN = 4,
LIBDECOR_WINDOW_STATE_TILED_LEFT = 8,
LIBDECOR_WINDOW_STATE_TILED_RIGHT = 16,
LIBDECOR_WINDOW_STATE_TILED_TOP = 32,
LIBDECOR_WINDOW_STATE_TILED_BOTTOM = 64
};
enum libdecor_capabilities
{
LIBDECOR_ACTION_MOVE = 1,
LIBDECOR_ACTION_RESIZE = 2,
LIBDECOR_ACTION_MINIMIZE = 4,
LIBDECOR_ACTION_FULLSCREEN = 8,
LIBDECOR_ACTION_CLOSE = 16
};
struct libdecor_interface
{
void (* error)(struct libdecor*,enum libdecor_error,const char*);
void (* reserved0)(void);
void (* reserved1)(void);
void (* reserved2)(void);
void (* reserved3)(void);
void (* reserved4)(void);
void (* reserved5)(void);
void (* reserved6)(void);
void (* reserved7)(void);
void (* reserved8)(void);
void (* reserved9)(void);
};
struct libdecor_frame_interface
{
void (* configure)(struct libdecor_frame*,struct libdecor_configuration*,void*);
void (* close)(struct libdecor_frame*,void*);
void (* commit)(struct libdecor_frame*,void*);
void (* dismiss_popup)(struct libdecor_frame*,const char*,void*);
void (* reserved0)(void);
void (* reserved1)(void);
void (* reserved2)(void);
void (* reserved3)(void);
void (* reserved4)(void);
void (* reserved5)(void);
void (* reserved6)(void);
void (* reserved7)(void);
void (* reserved8)(void);
void (* reserved9)(void);
};
typedef struct libdecor* (* PFN_libdecor_new)(struct wl_display*,const struct libdecor_interface*);
typedef void (* PFN_libdecor_unref)(struct libdecor*);
typedef int (* PFN_libdecor_get_fd)(struct libdecor*);
typedef int (* PFN_libdecor_dispatch)(struct libdecor*,int);
typedef struct libdecor_frame* (* PFN_libdecor_decorate)(struct libdecor*,struct wl_surface*,const struct libdecor_frame_interface*,void*);
typedef void (* PFN_libdecor_frame_unref)(struct libdecor_frame*);
typedef void (* PFN_libdecor_frame_set_app_id)(struct libdecor_frame*,const char*);
typedef void (* PFN_libdecor_frame_set_title)(struct libdecor_frame*,const char*);
typedef void (* PFN_libdecor_frame_set_minimized)(struct libdecor_frame*);
typedef void (* PFN_libdecor_frame_set_fullscreen)(struct libdecor_frame*,struct wl_output*);
typedef void (* PFN_libdecor_frame_unset_fullscreen)(struct libdecor_frame*);
typedef void (* PFN_libdecor_frame_map)(struct libdecor_frame*);
typedef void (* PFN_libdecor_frame_commit)(struct libdecor_frame*,struct libdecor_state*,struct libdecor_configuration*);
typedef void (* PFN_libdecor_frame_set_min_content_size)(struct libdecor_frame*,int,int);
typedef void (* PFN_libdecor_frame_set_max_content_size)(struct libdecor_frame*,int,int);
typedef void (* PFN_libdecor_frame_set_maximized)(struct libdecor_frame*);
typedef void (* PFN_libdecor_frame_unset_maximized)(struct libdecor_frame*);
typedef void (* PFN_libdecor_frame_set_capabilities)(struct libdecor_frame*,enum libdecor_capabilities);
typedef void (* PFN_libdecor_frame_unset_capabilities)(struct libdecor_frame*,enum libdecor_capabilities);
typedef void (* PFN_libdecor_frame_set_visibility)(struct libdecor_frame*,bool visible);
typedef struct xdg_toplevel* (* PFN_libdecor_frame_get_xdg_toplevel)(struct libdecor_frame*);
typedef bool (* PFN_libdecor_configuration_get_content_size)(struct libdecor_configuration*,struct libdecor_frame*,int*,int*);
typedef bool (* PFN_libdecor_configuration_get_window_state)(struct libdecor_configuration*,enum libdecor_window_state*);
typedef struct libdecor_state* (* PFN_libdecor_state_new)(int,int);
typedef void (* PFN_libdecor_state_free)(struct libdecor_state*);
#define libdecor_new _glfw.wl.libdecor.libdecor_new_
#define libdecor_unref _glfw.wl.libdecor.libdecor_unref_
#define libdecor_get_fd _glfw.wl.libdecor.libdecor_get_fd_
#define libdecor_dispatch _glfw.wl.libdecor.libdecor_dispatch_
#define libdecor_decorate _glfw.wl.libdecor.libdecor_decorate_
#define libdecor_frame_unref _glfw.wl.libdecor.libdecor_frame_unref_
#define libdecor_frame_set_app_id _glfw.wl.libdecor.libdecor_frame_set_app_id_
#define libdecor_frame_set_title _glfw.wl.libdecor.libdecor_frame_set_title_
#define libdecor_frame_set_minimized _glfw.wl.libdecor.libdecor_frame_set_minimized_
#define libdecor_frame_set_fullscreen _glfw.wl.libdecor.libdecor_frame_set_fullscreen_
#define libdecor_frame_unset_fullscreen _glfw.wl.libdecor.libdecor_frame_unset_fullscreen_
#define libdecor_frame_map _glfw.wl.libdecor.libdecor_frame_map_
#define libdecor_frame_commit _glfw.wl.libdecor.libdecor_frame_commit_
#define libdecor_frame_set_min_content_size _glfw.wl.libdecor.libdecor_frame_set_min_content_size_
#define libdecor_frame_set_max_content_size _glfw.wl.libdecor.libdecor_frame_set_max_content_size_
#define libdecor_frame_set_maximized _glfw.wl.libdecor.libdecor_frame_set_maximized_
#define libdecor_frame_unset_maximized _glfw.wl.libdecor.libdecor_frame_unset_maximized_
#define libdecor_frame_set_capabilities _glfw.wl.libdecor.libdecor_frame_set_capabilities_
#define libdecor_frame_unset_capabilities _glfw.wl.libdecor.libdecor_frame_unset_capabilities_
#define libdecor_frame_set_visibility _glfw.wl.libdecor.libdecor_frame_set_visibility_
#define libdecor_frame_get_xdg_toplevel _glfw.wl.libdecor.libdecor_frame_get_xdg_toplevel_
#define libdecor_configuration_get_content_size _glfw.wl.libdecor.libdecor_configuration_get_content_size_
#define libdecor_configuration_get_window_state _glfw.wl.libdecor.libdecor_configuration_get_window_state_
#define libdecor_state_new _glfw.wl.libdecor.libdecor_state_new_
#define libdecor_state_free _glfw.wl.libdecor.libdecor_state_free_
typedef enum _GLFWdecorationSideWayland typedef enum _GLFWdecorationSideWayland
{ {
mainWindow, GLFW_MAIN_WINDOW,
topDecoration, GLFW_TOP_DECORATION,
leftDecoration, GLFW_LEFT_DECORATION,
rightDecoration, GLFW_RIGHT_DECORATION,
bottomDecoration, GLFW_BOTTOM_DECORATION
} _GLFWdecorationSideWayland; } _GLFWdecorationSideWayland;
typedef struct _GLFWdecorationWayland typedef struct _GLFWdecorationWayland
@ -221,6 +344,12 @@ typedef struct _GLFWofferWayland
GLFWbool text_uri_list; GLFWbool text_uri_list;
} _GLFWofferWayland; } _GLFWofferWayland;
typedef struct _GLFWscaleWayland
{
struct wl_output* output;
int factor;
} _GLFWscaleWayland;
// Wayland-specific per-window data // Wayland-specific per-window data
// //
typedef struct _GLFWwindowWayland typedef struct _GLFWwindowWayland
@ -254,6 +383,11 @@ typedef struct _GLFWwindowWayland
uint32_t decorationMode; uint32_t decorationMode;
} xdg; } xdg;
struct {
struct libdecor_frame* frame;
int mode;
} libdecor;
_GLFWcursor* currentCursor; _GLFWcursor* currentCursor;
double cursorPosX, cursorPosY; double cursorPosX, cursorPosY;
@ -262,10 +396,10 @@ typedef struct _GLFWwindowWayland
// We need to track the monitors the window spans on to calculate the // We need to track the monitors the window spans on to calculate the
// optimal scaling factor. // optimal scaling factor.
int scale; int contentScale;
_GLFWmonitor** monitors; _GLFWscaleWayland* scales;
int monitorsCount; int scaleCount;
int monitorsSize; int scaleSize;
struct zwp_relative_pointer_v1* relativePointer; struct zwp_relative_pointer_v1* relativePointer;
struct zwp_locked_pointer_v1* lockedPointer; struct zwp_locked_pointer_v1* lockedPointer;
@ -311,8 +445,7 @@ typedef struct _GLFWlibraryWayland
_GLFWwindow* dragFocus; _GLFWwindow* dragFocus;
uint32_t dragSerial; uint32_t dragSerial;
int compositorVersion; const char* tag;
int seatVersion;
struct wl_cursor_theme* cursorTheme; struct wl_cursor_theme* cursorTheme;
struct wl_cursor_theme* cursorThemeHiDPI; struct wl_cursor_theme* cursorThemeHiDPI;
@ -391,6 +524,8 @@ typedef struct _GLFWlibraryWayland
PFN_wl_proxy_marshal_constructor_versioned proxy_marshal_constructor_versioned; PFN_wl_proxy_marshal_constructor_versioned proxy_marshal_constructor_versioned;
PFN_wl_proxy_get_user_data proxy_get_user_data; PFN_wl_proxy_get_user_data proxy_get_user_data;
PFN_wl_proxy_set_user_data proxy_set_user_data; PFN_wl_proxy_set_user_data proxy_set_user_data;
PFN_wl_proxy_get_tag proxy_get_tag;
PFN_wl_proxy_set_tag proxy_set_tag;
PFN_wl_proxy_get_version proxy_get_version; PFN_wl_proxy_get_version proxy_get_version;
PFN_wl_proxy_marshal_flags proxy_marshal_flags; PFN_wl_proxy_marshal_flags proxy_marshal_flags;
} client; } client;
@ -411,6 +546,36 @@ typedef struct _GLFWlibraryWayland
PFN_wl_egl_window_destroy window_destroy; PFN_wl_egl_window_destroy window_destroy;
PFN_wl_egl_window_resize window_resize; PFN_wl_egl_window_resize window_resize;
} egl; } egl;
struct {
void* handle;
struct libdecor* context;
PFN_libdecor_new libdecor_new_;
PFN_libdecor_unref libdecor_unref_;
PFN_libdecor_get_fd libdecor_get_fd_;
PFN_libdecor_dispatch libdecor_dispatch_;
PFN_libdecor_decorate libdecor_decorate_;
PFN_libdecor_frame_unref libdecor_frame_unref_;
PFN_libdecor_frame_set_app_id libdecor_frame_set_app_id_;
PFN_libdecor_frame_set_title libdecor_frame_set_title_;
PFN_libdecor_frame_set_minimized libdecor_frame_set_minimized_;
PFN_libdecor_frame_set_fullscreen libdecor_frame_set_fullscreen_;
PFN_libdecor_frame_unset_fullscreen libdecor_frame_unset_fullscreen_;
PFN_libdecor_frame_map libdecor_frame_map_;
PFN_libdecor_frame_commit libdecor_frame_commit_;
PFN_libdecor_frame_set_min_content_size libdecor_frame_set_min_content_size_;
PFN_libdecor_frame_set_max_content_size libdecor_frame_set_max_content_size_;
PFN_libdecor_frame_set_maximized libdecor_frame_set_maximized_;
PFN_libdecor_frame_unset_maximized libdecor_frame_unset_maximized_;
PFN_libdecor_frame_set_capabilities libdecor_frame_set_capabilities_;
PFN_libdecor_frame_unset_capabilities libdecor_frame_unset_capabilities_;
PFN_libdecor_frame_set_visibility libdecor_frame_set_visibility_;
PFN_libdecor_frame_get_xdg_toplevel libdecor_frame_get_xdg_toplevel_;
PFN_libdecor_configuration_get_content_size libdecor_configuration_get_content_size_;
PFN_libdecor_configuration_get_window_state libdecor_configuration_get_window_state_;
PFN_libdecor_state_new libdecor_state_new_;
PFN_libdecor_state_free libdecor_state_free_;
} libdecor;
} _GLFWlibraryWayland; } _GLFWlibraryWayland;
// Wayland-specific per-monitor data // Wayland-specific per-monitor data
@ -423,7 +588,7 @@ typedef struct _GLFWmonitorWayland
int x; int x;
int y; int y;
int scale; int contentScale;
} _GLFWmonitorWayland; } _GLFWmonitorWayland;
// Wayland-specific per-cursor data // Wayland-specific per-cursor data

View File

@ -192,13 +192,16 @@ static struct wl_buffer* createShmBuffer(const GLFWimage* image)
return buffer; return buffer;
} }
static void createFallbackDecoration(_GLFWdecorationWayland* decoration, static void createFallbackDecoration(_GLFWwindow* window,
_GLFWdecorationWayland* decoration,
struct wl_surface* parent, struct wl_surface* parent,
struct wl_buffer* buffer, struct wl_buffer* buffer,
int x, int y, int x, int y,
int width, int height) int width, int height)
{ {
decoration->surface = wl_compositor_create_surface(_glfw.wl.compositor); decoration->surface = wl_compositor_create_surface(_glfw.wl.compositor);
wl_surface_set_user_data(decoration->surface, window);
wl_proxy_set_tag((struct wl_proxy*) decoration->surface, &_glfw.wl.tag);
decoration->subsurface = decoration->subsurface =
wl_subcompositor_get_subsurface(_glfw.wl.subcompositor, wl_subcompositor_get_subsurface(_glfw.wl.subcompositor,
decoration->surface, parent); decoration->surface, parent);
@ -228,19 +231,19 @@ static void createFallbackDecorations(_GLFWwindow* window)
if (!window->wl.decorations.buffer) if (!window->wl.decorations.buffer)
return; return;
createFallbackDecoration(&window->wl.decorations.top, window->wl.surface, createFallbackDecoration(window, &window->wl.decorations.top, window->wl.surface,
window->wl.decorations.buffer, window->wl.decorations.buffer,
0, -GLFW_CAPTION_HEIGHT, 0, -GLFW_CAPTION_HEIGHT,
window->wl.width, GLFW_CAPTION_HEIGHT); window->wl.width, GLFW_CAPTION_HEIGHT);
createFallbackDecoration(&window->wl.decorations.left, window->wl.surface, createFallbackDecoration(window, &window->wl.decorations.left, window->wl.surface,
window->wl.decorations.buffer, window->wl.decorations.buffer,
-GLFW_BORDER_SIZE, -GLFW_CAPTION_HEIGHT, -GLFW_BORDER_SIZE, -GLFW_CAPTION_HEIGHT,
GLFW_BORDER_SIZE, window->wl.height + GLFW_CAPTION_HEIGHT); GLFW_BORDER_SIZE, window->wl.height + GLFW_CAPTION_HEIGHT);
createFallbackDecoration(&window->wl.decorations.right, window->wl.surface, createFallbackDecoration(window, &window->wl.decorations.right, window->wl.surface,
window->wl.decorations.buffer, window->wl.decorations.buffer,
window->wl.width, -GLFW_CAPTION_HEIGHT, window->wl.width, -GLFW_CAPTION_HEIGHT,
GLFW_BORDER_SIZE, window->wl.height + GLFW_CAPTION_HEIGHT); GLFW_BORDER_SIZE, window->wl.height + GLFW_CAPTION_HEIGHT);
createFallbackDecoration(&window->wl.decorations.bottom, window->wl.surface, createFallbackDecoration(window, &window->wl.decorations.bottom, window->wl.surface,
window->wl.decorations.buffer, window->wl.decorations.buffer,
-GLFW_BORDER_SIZE, window->wl.height, -GLFW_BORDER_SIZE, window->wl.height,
window->wl.width + GLFW_BORDER_SIZE * 2, GLFW_BORDER_SIZE); window->wl.width + GLFW_BORDER_SIZE * 2, GLFW_BORDER_SIZE);
@ -306,7 +309,7 @@ static void setContentAreaOpaque(_GLFWwindow* window)
static void resizeWindow(_GLFWwindow* window) static void resizeWindow(_GLFWwindow* window)
{ {
int scale = window->wl.scale; int scale = window->wl.contentScale;
int scaledWidth = window->wl.width * scale; int scaledWidth = window->wl.width * scale;
int scaledHeight = window->wl.height * scale; int scaledHeight = window->wl.height * scale;
@ -342,22 +345,28 @@ static void resizeWindow(_GLFWwindow* window)
void _glfwUpdateContentScaleWayland(_GLFWwindow* window) void _glfwUpdateContentScaleWayland(_GLFWwindow* window)
{ {
if (_glfw.wl.compositorVersion < WL_SURFACE_SET_BUFFER_SCALE_SINCE_VERSION) if (wl_compositor_get_version(_glfw.wl.compositor) <
WL_SURFACE_SET_BUFFER_SCALE_SINCE_VERSION)
{
return; return;
}
// Get the scale factor from the highest scale monitor. // Get the scale factor from the highest scale monitor.
int maxScale = 1; int maxScale = 1;
for (int i = 0; i < window->wl.monitorsCount; i++) for (int i = 0; i < window->wl.scaleCount; i++)
maxScale = _glfw_max(window->wl.monitors[i]->wl.scale, maxScale); maxScale = _glfw_max(window->wl.scales[i].factor, maxScale);
// Only change the framebuffer size if the scale changed. // Only change the framebuffer size if the scale changed.
if (window->wl.scale != maxScale) if (window->wl.contentScale != maxScale)
{ {
window->wl.scale = maxScale; window->wl.contentScale = maxScale;
wl_surface_set_buffer_scale(window->wl.surface, maxScale); wl_surface_set_buffer_scale(window->wl.surface, maxScale);
_glfwInputWindowContentScale(window, maxScale, maxScale); _glfwInputWindowContentScale(window, maxScale, maxScale);
resizeWindow(window); resizeWindow(window);
if (window->wl.visible)
_glfwInputWindowDamage(window);
} }
} }
@ -365,18 +374,25 @@ static void surfaceHandleEnter(void* userData,
struct wl_surface* surface, struct wl_surface* surface,
struct wl_output* output) struct wl_output* output)
{ {
if (wl_proxy_get_tag((struct wl_proxy*) output) != &_glfw.wl.tag)
return;
_GLFWwindow* window = userData; _GLFWwindow* window = userData;
_GLFWmonitor* monitor = wl_output_get_user_data(output); _GLFWmonitor* monitor = wl_output_get_user_data(output);
if (!window || !monitor)
return;
if (window->wl.monitorsCount + 1 > window->wl.monitorsSize) if (window->wl.scaleCount + 1 > window->wl.scaleSize)
{ {
++window->wl.monitorsSize; window->wl.scaleSize++;
window->wl.monitors = window->wl.scales =
_glfw_realloc(window->wl.monitors, _glfw_realloc(window->wl.scales,
window->wl.monitorsSize * sizeof(_GLFWmonitor*)); window->wl.scaleSize * sizeof(_GLFWscaleWayland));
} }
window->wl.monitors[window->wl.monitorsCount++] = monitor; window->wl.scaleCount++;
window->wl.scales[window->wl.scaleCount - 1].factor = monitor->wl.contentScale;
window->wl.scales[window->wl.scaleCount - 1].output = output;
_glfwUpdateContentScaleWayland(window); _glfwUpdateContentScaleWayland(window);
} }
@ -385,18 +401,20 @@ static void surfaceHandleLeave(void* userData,
struct wl_surface* surface, struct wl_surface* surface,
struct wl_output* output) struct wl_output* output)
{ {
_GLFWwindow* window = userData; if (wl_proxy_get_tag((struct wl_proxy*) output) != &_glfw.wl.tag)
_GLFWmonitor* monitor = wl_output_get_user_data(output); return;
GLFWbool found = GLFW_FALSE;
for (int i = 0; i < window->wl.monitorsCount - 1; ++i) _GLFWwindow* window = userData;
for (int i = 0; i < window->wl.scaleCount; i++)
{ {
if (monitor == window->wl.monitors[i]) if (window->wl.scales[i].output == output)
found = GLFW_TRUE; {
if (found) window->wl.scales[i] = window->wl.scales[window->wl.scaleCount - 1];
window->wl.monitors[i] = window->wl.monitors[i + 1]; window->wl.scaleCount--;
break;
}
} }
window->wl.monitors[--window->wl.monitorsCount] = NULL;
_glfwUpdateContentScaleWayland(window); _glfwUpdateContentScaleWayland(window);
} }
@ -429,7 +447,12 @@ static void setIdleInhibitor(_GLFWwindow* window, GLFWbool enable)
// //
static void acquireMonitor(_GLFWwindow* window) static void acquireMonitor(_GLFWwindow* window)
{ {
if (window->wl.xdg.toplevel) if (window->wl.libdecor.frame)
{
libdecor_frame_set_fullscreen(window->wl.libdecor.frame,
window->monitor->wl.output);
}
else if (window->wl.xdg.toplevel)
{ {
xdg_toplevel_set_fullscreen(window->wl.xdg.toplevel, xdg_toplevel_set_fullscreen(window->wl.xdg.toplevel,
window->monitor->wl.output); window->monitor->wl.output);
@ -445,12 +468,15 @@ static void acquireMonitor(_GLFWwindow* window)
// //
static void releaseMonitor(_GLFWwindow* window) static void releaseMonitor(_GLFWwindow* window)
{ {
if (window->wl.xdg.toplevel) if (window->wl.libdecor.frame)
libdecor_frame_unset_fullscreen(window->wl.libdecor.frame);
else if (window->wl.xdg.toplevel)
xdg_toplevel_unset_fullscreen(window->wl.xdg.toplevel); xdg_toplevel_unset_fullscreen(window->wl.xdg.toplevel);
setIdleInhibitor(window, GLFW_FALSE); setIdleInhibitor(window, GLFW_FALSE);
if (window->wl.xdg.decorationMode != ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE) if (!window->wl.libdecor.frame &&
window->wl.xdg.decorationMode != ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE)
{ {
if (window->decorated) if (window->decorated)
createFallbackDecorations(window); createFallbackDecorations(window);
@ -593,7 +619,190 @@ static const struct xdg_surface_listener xdgSurfaceListener =
xdgSurfaceHandleConfigure xdgSurfaceHandleConfigure
}; };
static GLFWbool createShellObjects(_GLFWwindow* window) void libdecorFrameHandleConfigure(struct libdecor_frame* frame,
struct libdecor_configuration* config,
void* userData)
{
_GLFWwindow* window = userData;
int width, height;
enum libdecor_window_state windowState;
GLFWbool fullscreen, activated, maximized;
if (libdecor_configuration_get_window_state(config, &windowState))
{
fullscreen = (windowState & LIBDECOR_WINDOW_STATE_FULLSCREEN) != 0;
activated = (windowState & LIBDECOR_WINDOW_STATE_ACTIVE) != 0;
maximized = (windowState & LIBDECOR_WINDOW_STATE_MAXIMIZED) != 0;
}
else
{
fullscreen = window->wl.fullscreen;
activated = window->wl.activated;
maximized = window->wl.maximized;
}
if (!libdecor_configuration_get_content_size(config, frame, &width, &height))
{
width = window->wl.width;
height = window->wl.height;
}
if (!maximized && !fullscreen)
{
if (window->numer != GLFW_DONT_CARE && window->denom != GLFW_DONT_CARE)
{
const float aspectRatio = (float) width / (float) height;
const float targetRatio = (float) window->numer / (float) window->denom;
if (aspectRatio < targetRatio)
height = width / targetRatio;
else if (aspectRatio > targetRatio)
width = height * targetRatio;
}
}
struct libdecor_state* frameState = libdecor_state_new(width, height);
libdecor_frame_commit(frame, frameState, config);
libdecor_state_free(frameState);
if (window->wl.activated != activated)
{
window->wl.activated = activated;
if (!window->wl.activated)
{
if (window->monitor && window->autoIconify)
libdecor_frame_set_minimized(window->wl.libdecor.frame);
}
}
if (window->wl.maximized != maximized)
{
window->wl.maximized = maximized;
_glfwInputWindowMaximize(window, window->wl.maximized);
}
window->wl.fullscreen = fullscreen;
GLFWbool damaged = GLFW_FALSE;
if (!window->wl.visible)
{
window->wl.visible = GLFW_TRUE;
damaged = GLFW_TRUE;
}
if (width != window->wl.width || height != window->wl.height)
{
window->wl.width = width;
window->wl.height = height;
resizeWindow(window);
_glfwInputWindowSize(window, width, height);
damaged = GLFW_TRUE;
}
if (damaged)
_glfwInputWindowDamage(window);
else
wl_surface_commit(window->wl.surface);
}
void libdecorFrameHandleClose(struct libdecor_frame* frame, void* userData)
{
_GLFWwindow* window = userData;
_glfwInputWindowCloseRequest(window);
}
void libdecorFrameHandleCommit(struct libdecor_frame* frame, void* userData)
{
_GLFWwindow* window = userData;
wl_surface_commit(window->wl.surface);
}
void libdecorFrameHandleDismissPopup(struct libdecor_frame* frame,
const char* seatName,
void* userData)
{
}
static const struct libdecor_frame_interface libdecorFrameInterface =
{
libdecorFrameHandleConfigure,
libdecorFrameHandleClose,
libdecorFrameHandleCommit,
libdecorFrameHandleDismissPopup
};
static GLFWbool createLibdecorFrame(_GLFWwindow* window)
{
window->wl.libdecor.frame = libdecor_decorate(_glfw.wl.libdecor.context,
window->wl.surface,
&libdecorFrameInterface,
window);
if (!window->wl.libdecor.frame)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: Failed to create libdecor frame");
return GLFW_FALSE;
}
if (strlen(window->wl.appId))
libdecor_frame_set_app_id(window->wl.libdecor.frame, window->wl.appId);
if (strlen(window->wl.title))
libdecor_frame_set_title(window->wl.libdecor.frame, window->wl.title);
if (window->minwidth != GLFW_DONT_CARE &&
window->minheight != GLFW_DONT_CARE)
{
libdecor_frame_set_min_content_size(window->wl.libdecor.frame,
window->minwidth,
window->minheight);
}
if (window->maxwidth != GLFW_DONT_CARE &&
window->maxheight != GLFW_DONT_CARE)
{
libdecor_frame_set_max_content_size(window->wl.libdecor.frame,
window->maxwidth,
window->maxheight);
}
if (!window->resizable)
{
libdecor_frame_unset_capabilities(window->wl.libdecor.frame,
LIBDECOR_ACTION_RESIZE);
}
if (window->monitor)
{
// HACK: Allow libdecor to finish initialization of itself and its
// plugin so it will create the xdg_toplevel for the frame
// This needs to exist when setting the frame to fullscreen
while (!libdecor_frame_get_xdg_toplevel(window->wl.libdecor.frame))
_glfwWaitEventsWayland();
libdecor_frame_set_fullscreen(window->wl.libdecor.frame,
window->monitor->wl.output);
setIdleInhibitor(window, GLFW_TRUE);
}
else
{
if (window->wl.maximized)
libdecor_frame_set_maximized(window->wl.libdecor.frame);
if (!window->decorated)
libdecor_frame_set_visibility(window->wl.libdecor.frame, false);
setIdleInhibitor(window, GLFW_FALSE);
}
libdecor_frame_map(window->wl.libdecor.frame);
wl_display_roundtrip(_glfw.wl.display);
return GLFW_TRUE;
}
static GLFWbool createXdgShellObjects(_GLFWwindow* window)
{ {
window->wl.xdg.surface = xdg_wm_base_get_xdg_surface(_glfw.wl.wmBase, window->wl.xdg.surface = xdg_wm_base_get_xdg_surface(_glfw.wl.wmBase,
window->wl.surface); window->wl.surface);
@ -633,30 +842,30 @@ static GLFWbool createShellObjects(_GLFWwindow* window)
xdg_toplevel_set_maximized(window->wl.xdg.toplevel); xdg_toplevel_set_maximized(window->wl.xdg.toplevel);
setIdleInhibitor(window, GLFW_FALSE); setIdleInhibitor(window, GLFW_FALSE);
}
if (_glfw.wl.decorationManager) if (_glfw.wl.decorationManager)
{ {
window->wl.xdg.decoration = window->wl.xdg.decoration =
zxdg_decoration_manager_v1_get_toplevel_decoration( zxdg_decoration_manager_v1_get_toplevel_decoration(
_glfw.wl.decorationManager, window->wl.xdg.toplevel); _glfw.wl.decorationManager, window->wl.xdg.toplevel);
zxdg_toplevel_decoration_v1_add_listener(window->wl.xdg.decoration, zxdg_toplevel_decoration_v1_add_listener(window->wl.xdg.decoration,
&xdgDecorationListener, &xdgDecorationListener,
window); window);
uint32_t mode; uint32_t mode;
if (window->decorated) if (window->decorated)
mode = ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE; mode = ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE;
else
mode = ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE;
zxdg_toplevel_decoration_v1_set_mode(window->wl.xdg.decoration, mode);
}
else else
{ mode = ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE;
if (window->decorated)
createFallbackDecorations(window); zxdg_toplevel_decoration_v1_set_mode(window->wl.xdg.decoration, mode);
} }
else
{
if (window->decorated && !window->monitor)
createFallbackDecorations(window);
} }
if (window->minwidth != GLFW_DONT_CARE && window->minheight != GLFW_DONT_CARE) if (window->minwidth != GLFW_DONT_CARE && window->minheight != GLFW_DONT_CARE)
@ -689,14 +898,27 @@ static GLFWbool createShellObjects(_GLFWwindow* window)
wl_surface_commit(window->wl.surface); wl_surface_commit(window->wl.surface);
wl_display_roundtrip(_glfw.wl.display); wl_display_roundtrip(_glfw.wl.display);
return GLFW_TRUE; return GLFW_TRUE;
} }
static GLFWbool createShellObjects(_GLFWwindow* window)
{
if (_glfw.wl.libdecor.context)
{
if (createLibdecorFrame(window))
return GLFW_TRUE;
}
return createXdgShellObjects(window);
}
static void destroyShellObjects(_GLFWwindow* window) static void destroyShellObjects(_GLFWwindow* window)
{ {
destroyFallbackDecorations(window); destroyFallbackDecorations(window);
if (window->wl.libdecor.frame)
libdecor_frame_unref(window->wl.libdecor.frame);
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);
@ -706,6 +928,7 @@ static void destroyShellObjects(_GLFWwindow* window)
if (window->wl.xdg.surface) if (window->wl.xdg.surface)
xdg_surface_destroy(window->wl.xdg.surface); xdg_surface_destroy(window->wl.xdg.surface);
window->wl.libdecor.frame = NULL;
window->wl.xdg.decoration = NULL; window->wl.xdg.decoration = NULL;
window->wl.xdg.decorationMode = 0; window->wl.xdg.decorationMode = 0;
window->wl.xdg.toplevel = NULL; window->wl.xdg.toplevel = NULL;
@ -723,15 +946,14 @@ static GLFWbool createNativeSurface(_GLFWwindow* window,
return GLFW_FALSE; return GLFW_FALSE;
} }
wl_proxy_set_tag((struct wl_proxy*) window->wl.surface, &_glfw.wl.tag);
wl_surface_add_listener(window->wl.surface, wl_surface_add_listener(window->wl.surface,
&surfaceListener, &surfaceListener,
window); window);
wl_surface_set_user_data(window->wl.surface, window);
window->wl.width = wndconfig->width; window->wl.width = wndconfig->width;
window->wl.height = wndconfig->height; window->wl.height = wndconfig->height;
window->wl.scale = 1; window->wl.contentScale = 1;
window->wl.title = _glfw_strdup(wndconfig->title); window->wl.title = _glfw_strdup(wndconfig->title);
window->wl.appId = _glfw_strdup(wndconfig->wl.appId); window->wl.appId = _glfw_strdup(wndconfig->wl.appId);
@ -758,7 +980,7 @@ static void setCursorImage(_GLFWwindow* window,
buffer = cursorWayland->buffer; buffer = cursorWayland->buffer;
else else
{ {
if (window->wl.scale > 1 && cursorWayland->cursorHiDPI) if (window->wl.contentScale > 1 && cursorWayland->cursorHiDPI)
{ {
wlCursor = cursorWayland->cursorHiDPI; wlCursor = cursorWayland->cursorHiDPI;
scale = 2; scale = 2;
@ -794,7 +1016,7 @@ static void incrementCursorImage(_GLFWwindow* window)
{ {
_GLFWcursor* cursor; _GLFWcursor* cursor;
if (!window || window->wl.decorations.focus != mainWindow) if (!window || window->wl.decorations.focus != GLFW_MAIN_WINDOW)
return; return;
cursor = window->wl.currentCursor; cursor = window->wl.currentCursor;
@ -874,13 +1096,17 @@ static void inputText(_GLFWwindow* window, uint32_t scancode)
static void handleEvents(double* timeout) static void handleEvents(double* timeout)
{ {
GLFWbool event = GLFW_FALSE; GLFWbool event = GLFW_FALSE;
struct pollfd fds[] = struct pollfd fds[4] =
{ {
{ wl_display_get_fd(_glfw.wl.display), POLLIN }, { wl_display_get_fd(_glfw.wl.display), POLLIN },
{ _glfw.wl.keyRepeatTimerfd, POLLIN }, { _glfw.wl.keyRepeatTimerfd, POLLIN },
{ _glfw.wl.cursorTimerfd, POLLIN }, { _glfw.wl.cursorTimerfd, POLLIN },
{ -1, POLLIN }
}; };
if (_glfw.wl.libdecor.context)
fds[3].fd = libdecor_get_fd(_glfw.wl.libdecor.context);
while (!event) while (!event)
{ {
while (wl_display_prepare_read(_glfw.wl.display) != 0) while (wl_display_prepare_read(_glfw.wl.display) != 0)
@ -902,7 +1128,7 @@ static void handleEvents(double* timeout)
return; return;
} }
if (!_glfwPollPOSIX(fds, 3, timeout)) if (!_glfwPollPOSIX(fds, sizeof(fds) / sizeof(fds[0]), timeout))
{ {
wl_display_cancel_read(_glfw.wl.display); wl_display_cancel_read(_glfw.wl.display);
return; return;
@ -947,6 +1173,9 @@ static void handleEvents(double* timeout)
event = GLFW_TRUE; event = GLFW_TRUE;
} }
} }
if (fds[3].revents & POLLIN)
libdecor_dispatch(_glfw.wl.libdecor.context, 0);
} }
} }
@ -1014,40 +1243,6 @@ static char* readDataOfferAsString(struct wl_data_offer* offer, const char* mime
return string; return string;
} }
static _GLFWwindow* findWindowFromDecorationSurface(struct wl_surface* surface,
_GLFWdecorationSideWayland* which)
{
_GLFWdecorationSideWayland focus;
_GLFWwindow* window = _glfw.windowListHead;
if (!which)
which = &focus;
while (window)
{
if (surface == window->wl.decorations.top.surface)
{
*which = topDecoration;
break;
}
if (surface == window->wl.decorations.left.surface)
{
*which = leftDecoration;
break;
}
if (surface == window->wl.decorations.right.surface)
{
*which = rightDecoration;
break;
}
if (surface == window->wl.decorations.bottom.surface)
{
*which = bottomDecoration;
break;
}
window = window->next;
}
return window;
}
static void pointerHandleEnter(void* userData, static void pointerHandleEnter(void* userData,
struct wl_pointer* pointer, struct wl_pointer* pointer,
uint32_t serial, uint32_t serial,
@ -1059,16 +1254,22 @@ static void pointerHandleEnter(void* userData,
if (!surface) if (!surface)
return; return;
_GLFWdecorationSideWayland focus = mainWindow; if (wl_proxy_get_tag((struct wl_proxy*) surface) != &_glfw.wl.tag)
_GLFWwindow* window = wl_surface_get_user_data(surface); return;
if (!window)
{ _GLFWwindow* window = wl_surface_get_user_data(surface);
window = findWindowFromDecorationSurface(surface, &focus);
if (!window) if (surface == window->wl.decorations.top.surface)
return; window->wl.decorations.focus = GLFW_TOP_DECORATION;
} else if (surface == window->wl.decorations.left.surface)
window->wl.decorations.focus = GLFW_LEFT_DECORATION;
else if (surface == window->wl.decorations.right.surface)
window->wl.decorations.focus = GLFW_RIGHT_DECORATION;
else if (surface == window->wl.decorations.bottom.surface)
window->wl.decorations.focus = GLFW_BOTTOM_DECORATION;
else
window->wl.decorations.focus = GLFW_MAIN_WINDOW;
window->wl.decorations.focus = focus;
_glfw.wl.serial = serial; _glfw.wl.serial = serial;
_glfw.wl.pointerEnterSerial = serial; _glfw.wl.pointerEnterSerial = serial;
_glfw.wl.pointerFocus = window; _glfw.wl.pointerFocus = window;
@ -1084,8 +1285,13 @@ static void pointerHandleLeave(void* userData,
uint32_t serial, uint32_t serial,
struct wl_surface* surface) struct wl_surface* surface)
{ {
_GLFWwindow* window = _glfw.wl.pointerFocus; if (!surface)
return;
if (wl_proxy_get_tag((struct wl_proxy*) surface) != &_glfw.wl.tag)
return;
_GLFWwindow* window = _glfw.wl.pointerFocus;
if (!window) if (!window)
return; return;
@ -1106,7 +1312,7 @@ static void setCursor(_GLFWwindow* window, const char* name)
struct wl_cursor_theme* theme = _glfw.wl.cursorTheme; struct wl_cursor_theme* theme = _glfw.wl.cursorTheme;
int scale = 1; int scale = 1;
if (window->wl.scale > 1 && _glfw.wl.cursorThemeHiDPI) if (window->wl.contentScale > 1 && _glfw.wl.cursorThemeHiDPI)
{ {
// We only support up to scale=2 for now, since libwayland-cursor // We only support up to scale=2 for now, since libwayland-cursor
// requires us to load a different theme for each size. // requires us to load a different theme for each size.
@ -1164,29 +1370,29 @@ static void pointerHandleMotion(void* userData,
switch (window->wl.decorations.focus) switch (window->wl.decorations.focus)
{ {
case mainWindow: case GLFW_MAIN_WINDOW:
_glfw.wl.cursorPreviousName = NULL; _glfw.wl.cursorPreviousName = NULL;
_glfwInputCursorPos(window, x, y); _glfwInputCursorPos(window, x, y);
return; return;
case topDecoration: case GLFW_TOP_DECORATION:
if (y < GLFW_BORDER_SIZE) if (y < GLFW_BORDER_SIZE)
cursorName = "n-resize"; cursorName = "n-resize";
else else
cursorName = "left_ptr"; cursorName = "left_ptr";
break; break;
case leftDecoration: case GLFW_LEFT_DECORATION:
if (y < GLFW_BORDER_SIZE) if (y < GLFW_BORDER_SIZE)
cursorName = "nw-resize"; cursorName = "nw-resize";
else else
cursorName = "w-resize"; cursorName = "w-resize";
break; break;
case rightDecoration: case GLFW_RIGHT_DECORATION:
if (y < GLFW_BORDER_SIZE) if (y < GLFW_BORDER_SIZE)
cursorName = "ne-resize"; cursorName = "ne-resize";
else else
cursorName = "e-resize"; cursorName = "e-resize";
break; break;
case bottomDecoration: case GLFW_BOTTOM_DECORATION:
if (x < GLFW_BORDER_SIZE) if (x < GLFW_BORDER_SIZE)
cursorName = "sw-resize"; cursorName = "sw-resize";
else if (x > window->wl.width + GLFW_BORDER_SIZE) else if (x > window->wl.width + GLFW_BORDER_SIZE)
@ -1218,27 +1424,27 @@ static void pointerHandleButton(void* userData,
{ {
switch (window->wl.decorations.focus) switch (window->wl.decorations.focus)
{ {
case mainWindow: case GLFW_MAIN_WINDOW:
break; break;
case topDecoration: case GLFW_TOP_DECORATION:
if (window->wl.cursorPosY < GLFW_BORDER_SIZE) if (window->wl.cursorPosY < GLFW_BORDER_SIZE)
edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP; edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP;
else else
xdg_toplevel_move(window->wl.xdg.toplevel, _glfw.wl.seat, serial); xdg_toplevel_move(window->wl.xdg.toplevel, _glfw.wl.seat, serial);
break; break;
case leftDecoration: case GLFW_LEFT_DECORATION:
if (window->wl.cursorPosY < GLFW_BORDER_SIZE) if (window->wl.cursorPosY < GLFW_BORDER_SIZE)
edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT; edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT;
else else
edges = XDG_TOPLEVEL_RESIZE_EDGE_LEFT; edges = XDG_TOPLEVEL_RESIZE_EDGE_LEFT;
break; break;
case rightDecoration: case GLFW_RIGHT_DECORATION:
if (window->wl.cursorPosY < GLFW_BORDER_SIZE) if (window->wl.cursorPosY < GLFW_BORDER_SIZE)
edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT; edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT;
else else
edges = XDG_TOPLEVEL_RESIZE_EDGE_RIGHT; edges = XDG_TOPLEVEL_RESIZE_EDGE_RIGHT;
break; break;
case bottomDecoration: case GLFW_BOTTOM_DECORATION:
if (window->wl.cursorPosX < GLFW_BORDER_SIZE) if (window->wl.cursorPosX < GLFW_BORDER_SIZE)
edges = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT; edges = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT;
else if (window->wl.cursorPosX > window->wl.width + GLFW_BORDER_SIZE) else if (window->wl.cursorPosX > window->wl.width + GLFW_BORDER_SIZE)
@ -1258,7 +1464,8 @@ static void pointerHandleButton(void* userData,
} }
else if (button == BTN_RIGHT) else if (button == BTN_RIGHT)
{ {
if (window->wl.decorations.focus != mainWindow && window->wl.xdg.toplevel) if (window->wl.decorations.focus != GLFW_MAIN_WINDOW &&
window->wl.xdg.toplevel)
{ {
xdg_toplevel_show_window_menu(window->wl.xdg.toplevel, xdg_toplevel_show_window_menu(window->wl.xdg.toplevel,
_glfw.wl.seat, serial, _glfw.wl.seat, serial,
@ -1269,7 +1476,7 @@ static void pointerHandleButton(void* userData,
} }
// 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 != GLFW_MAIN_WINDOW)
return; return;
_glfw.wl.serial = serial; _glfw.wl.serial = serial;
@ -1423,13 +1630,12 @@ static void keyboardHandleEnter(void* userData,
if (!surface) if (!surface)
return; return;
if (wl_proxy_get_tag((struct wl_proxy*) surface) != &_glfw.wl.tag)
return;
_GLFWwindow* window = wl_surface_get_user_data(surface); _GLFWwindow* window = wl_surface_get_user_data(surface);
if (!window) if (surface != window->wl.surface)
{ return;
window = findWindowFromDecorationSurface(surface, NULL);
if (!window)
return;
}
_glfw.wl.serial = serial; _glfw.wl.serial = serial;
_glfw.wl.keyboardFocus = window; _glfw.wl.keyboardFocus = window;
@ -1640,7 +1846,8 @@ static void dataDeviceHandleDataOffer(void* userData,
struct wl_data_offer* offer) struct wl_data_offer* offer)
{ {
_GLFWofferWayland* offers = _GLFWofferWayland* offers =
_glfw_realloc(_glfw.wl.offers, _glfw.wl.offerCount + 1); _glfw_realloc(_glfw.wl.offers,
sizeof(_GLFWofferWayland) * (_glfw.wl.offerCount + 1));
if (!offers) if (!offers)
{ {
_glfwInputError(GLFW_OUT_OF_MEMORY, NULL); _glfwInputError(GLFW_OUT_OF_MEMORY, NULL);
@ -1676,9 +1883,12 @@ static void dataDeviceHandleEnter(void* userData,
_GLFWwindow* window = NULL; _GLFWwindow* window = NULL;
if (surface) if (surface)
window = wl_surface_get_user_data(surface); {
if (wl_proxy_get_tag((struct wl_proxy*) surface) == &_glfw.wl.tag)
window = wl_surface_get_user_data(surface);
}
if (window && _glfw.wl.offers[i].text_uri_list) if (surface == window->wl.surface && _glfw.wl.offers[i].text_uri_list)
{ {
_glfw.wl.dragOffer = offer; _glfw.wl.dragOffer = offer;
_glfw.wl.dragFocus = window; _glfw.wl.dragFocus = window;
@ -1691,6 +1901,9 @@ static void dataDeviceHandleEnter(void* userData,
} }
} }
if (wl_proxy_get_tag((struct wl_proxy*) surface) != &_glfw.wl.tag)
return;
if (_glfw.wl.dragOffer) if (_glfw.wl.dragOffer)
wl_data_offer_accept(offer, serial, "text/uri-list"); wl_data_offer_accept(offer, serial, "text/uri-list");
else else
@ -1881,7 +2094,7 @@ void _glfwDestroyWindowWayland(_GLFWwindow* window)
_glfw_free(window->wl.title); _glfw_free(window->wl.title);
_glfw_free(window->wl.appId); _glfw_free(window->wl.appId);
_glfw_free(window->wl.monitors); _glfw_free(window->wl.scales);
} }
void _glfwSetWindowTitleWayland(_GLFWwindow* window, const char* title) void _glfwSetWindowTitleWayland(_GLFWwindow* window, const char* title)
@ -1890,7 +2103,9 @@ void _glfwSetWindowTitleWayland(_GLFWwindow* window, const char* title)
_glfw_free(window->wl.title); _glfw_free(window->wl.title);
window->wl.title = copy; window->wl.title = copy;
if (window->wl.xdg.toplevel) if (window->wl.libdecor.frame)
libdecor_frame_set_title(window->wl.libdecor.frame, title);
else if (window->wl.xdg.toplevel)
xdg_toplevel_set_title(window->wl.xdg.toplevel, title); xdg_toplevel_set_title(window->wl.xdg.toplevel, title);
} }
@ -1937,6 +2152,16 @@ void _glfwSetWindowSizeWayland(_GLFWwindow* window, int width, int height)
window->wl.width = width; window->wl.width = width;
window->wl.height = height; window->wl.height = height;
resizeWindow(window); resizeWindow(window);
if (window->wl.libdecor.frame)
{
struct libdecor_state* frameState = libdecor_state_new(width, height);
libdecor_frame_commit(window->wl.libdecor.frame, frameState, NULL);
libdecor_state_free(frameState);
}
if (window->wl.visible)
_glfwInputWindowDamage(window);
} }
} }
@ -1944,7 +2169,20 @@ void _glfwSetWindowSizeLimitsWayland(_GLFWwindow* window,
int minwidth, int minheight, int minwidth, int minheight,
int maxwidth, int maxheight) int maxwidth, int maxheight)
{ {
if (window->wl.xdg.toplevel) if (window->wl.libdecor.frame)
{
if (minwidth == GLFW_DONT_CARE || minheight == GLFW_DONT_CARE)
minwidth = minheight = 0;
if (maxwidth == GLFW_DONT_CARE || maxheight == GLFW_DONT_CARE)
maxwidth = maxheight = 0;
libdecor_frame_set_min_content_size(window->wl.libdecor.frame,
minwidth, minheight);
libdecor_frame_set_max_content_size(window->wl.libdecor.frame,
maxwidth, maxheight);
}
else if (window->wl.xdg.toplevel)
{ {
if (minwidth == GLFW_DONT_CARE || minheight == GLFW_DONT_CARE) if (minwidth == GLFW_DONT_CARE || minheight == GLFW_DONT_CARE)
minwidth = minheight = 0; minwidth = minheight = 0;
@ -1979,16 +2217,35 @@ void _glfwSetWindowAspectRatioWayland(_GLFWwindow* window, int numer, int denom)
if (window->wl.maximized || window->wl.fullscreen) if (window->wl.maximized || window->wl.fullscreen)
return; return;
int width = window->wl.width, height = window->wl.height;
if (numer != GLFW_DONT_CARE && denom != GLFW_DONT_CARE) if (numer != GLFW_DONT_CARE && denom != GLFW_DONT_CARE)
{ {
const float aspectRatio = (float) window->wl.width / (float) window->wl.height; const float aspectRatio = (float) width / (float) height;
const float targetRatio = (float) numer / (float) denom; const float targetRatio = (float) numer / (float) denom;
if (aspectRatio < targetRatio) if (aspectRatio < targetRatio)
window->wl.height = window->wl.width / targetRatio; height /= targetRatio;
else if (aspectRatio > targetRatio) else if (aspectRatio > targetRatio)
window->wl.width = window->wl.height * targetRatio; width *= targetRatio;
}
if (width != window->wl.width || height != window->wl.height)
{
window->wl.width = width;
window->wl.height = height;
resizeWindow(window); resizeWindow(window);
if (window->wl.libdecor.frame)
{
struct libdecor_state* frameState = libdecor_state_new(width, height);
libdecor_frame_commit(window->wl.libdecor.frame, frameState, NULL);
libdecor_state_free(frameState);
}
_glfwInputWindowSize(window, width, height);
if (window->wl.visible)
_glfwInputWindowDamage(window);
} }
} }
@ -1996,16 +2253,16 @@ void _glfwGetFramebufferSizeWayland(_GLFWwindow* window, int* width, int* height
{ {
_glfwGetWindowSizeWayland(window, width, height); _glfwGetWindowSizeWayland(window, width, height);
if (width) if (width)
*width *= window->wl.scale; *width *= window->wl.contentScale;
if (height) if (height)
*height *= window->wl.scale; *height *= window->wl.contentScale;
} }
void _glfwGetWindowFrameSizeWayland(_GLFWwindow* window, void _glfwGetWindowFrameSizeWayland(_GLFWwindow* window,
int* left, int* top, int* left, int* top,
int* right, int* bottom) int* right, int* bottom)
{ {
if (window->decorated && !window->monitor && window->wl.decorations.top.surface) if (window->wl.decorations.top.surface)
{ {
if (top) if (top)
*top = GLFW_CAPTION_HEIGHT; *top = GLFW_CAPTION_HEIGHT;
@ -2022,14 +2279,16 @@ void _glfwGetWindowContentScaleWayland(_GLFWwindow* window,
float* xscale, float* yscale) float* xscale, float* yscale)
{ {
if (xscale) if (xscale)
*xscale = (float) window->wl.scale; *xscale = (float) window->wl.contentScale;
if (yscale) if (yscale)
*yscale = (float) window->wl.scale; *yscale = (float) window->wl.contentScale;
} }
void _glfwIconifyWindowWayland(_GLFWwindow* window) void _glfwIconifyWindowWayland(_GLFWwindow* window)
{ {
if (window->wl.xdg.toplevel) if (window->wl.libdecor.frame)
libdecor_frame_set_minimized(window->wl.libdecor.frame);
else if (window->wl.xdg.toplevel)
xdg_toplevel_set_minimized(window->wl.xdg.toplevel); xdg_toplevel_set_minimized(window->wl.xdg.toplevel);
} }
@ -2046,7 +2305,9 @@ void _glfwRestoreWindowWayland(_GLFWwindow* window)
if (window->wl.maximized) if (window->wl.maximized)
{ {
if (window->wl.xdg.toplevel) if (window->wl.libdecor.frame)
libdecor_frame_unset_maximized(window->wl.libdecor.frame);
else if (window->wl.xdg.toplevel)
xdg_toplevel_unset_maximized(window->wl.xdg.toplevel); xdg_toplevel_unset_maximized(window->wl.xdg.toplevel);
else else
window->wl.maximized = GLFW_FALSE; window->wl.maximized = GLFW_FALSE;
@ -2056,7 +2317,9 @@ void _glfwRestoreWindowWayland(_GLFWwindow* window)
void _glfwMaximizeWindowWayland(_GLFWwindow* window) void _glfwMaximizeWindowWayland(_GLFWwindow* window)
{ {
if (window->wl.xdg.toplevel) if (window->wl.libdecor.frame)
libdecor_frame_set_maximized(window->wl.libdecor.frame);
else if (window->wl.xdg.toplevel)
xdg_toplevel_set_maximized(window->wl.xdg.toplevel); xdg_toplevel_set_maximized(window->wl.xdg.toplevel);
else else
window->wl.maximized = GLFW_TRUE; window->wl.maximized = GLFW_TRUE;
@ -2064,7 +2327,7 @@ void _glfwMaximizeWindowWayland(_GLFWwindow* window)
void _glfwShowWindowWayland(_GLFWwindow* window) void _glfwShowWindowWayland(_GLFWwindow* window)
{ {
if (!window->wl.xdg.toplevel) if (!window->wl.libdecor.frame && !window->wl.xdg.toplevel)
{ {
// NOTE: The XDG surface and role are created here so command-line applications // NOTE: The XDG surface and role are created here so command-line applications
// with off-screen windows do not appear in for example the Unity dock // with off-screen windows do not appear in for example the Unity dock
@ -2161,14 +2424,34 @@ GLFWbool _glfwFramebufferTransparentWayland(_GLFWwindow* window)
void _glfwSetWindowResizableWayland(_GLFWwindow* window, GLFWbool enabled) void _glfwSetWindowResizableWayland(_GLFWwindow* window, GLFWbool enabled)
{ {
// TODO if (window->wl.libdecor.frame)
_glfwInputError(GLFW_FEATURE_UNIMPLEMENTED, {
"Wayland: Window attribute setting not implemented yet"); if (enabled)
{
libdecor_frame_set_capabilities(window->wl.libdecor.frame,
LIBDECOR_ACTION_RESIZE);
}
else
{
libdecor_frame_unset_capabilities(window->wl.libdecor.frame,
LIBDECOR_ACTION_RESIZE);
}
}
else
{
// TODO
_glfwInputError(GLFW_FEATURE_UNIMPLEMENTED,
"Wayland: Window attribute setting not implemented yet");
}
} }
void _glfwSetWindowDecoratedWayland(_GLFWwindow* window, GLFWbool enabled) void _glfwSetWindowDecoratedWayland(_GLFWwindow* window, GLFWbool enabled)
{ {
if (window->wl.xdg.decoration) if (window->wl.libdecor.frame)
{
libdecor_frame_set_visibility(window->wl.libdecor.frame, enabled);
}
else if (window->wl.xdg.decoration)
{ {
uint32_t mode; uint32_t mode;
@ -2179,7 +2462,7 @@ void _glfwSetWindowDecoratedWayland(_GLFWwindow* window, GLFWbool enabled)
zxdg_toplevel_decoration_v1_set_mode(window->wl.xdg.decoration, mode); zxdg_toplevel_decoration_v1_set_mode(window->wl.xdg.decoration, mode);
} }
else else if (window->wl.xdg.toplevel)
{ {
if (enabled) if (enabled)
createFallbackDecorations(window); createFallbackDecorations(window);
@ -2589,8 +2872,11 @@ void _glfwSetCursorWayland(_GLFWwindow* window, _GLFWcursor* cursor)
// 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 != _glfw.wl.pointerFocus ||
window->wl.decorations.focus != GLFW_MAIN_WINDOW)
{
return; return;
}
// Update pointer lock to match cursor mode // Update pointer lock to match cursor mode
if (window->cursorMode == GLFW_CURSOR_DISABLED) if (window->cursorMode == GLFW_CURSOR_DISABLED)

View File

@ -1184,7 +1184,7 @@ GLFWbool _glfwConnectX11(int platformID, _GLFWplatform* platform)
_glfwGetKeyScancodeX11, _glfwGetKeyScancodeX11,
_glfwSetClipboardStringX11, _glfwSetClipboardStringX11,
_glfwGetClipboardStringX11, _glfwGetClipboardStringX11,
#if defined(_GLFW_LINUX_JOYSTICK) #if defined(GLFW_BUILD_LINUX_JOYSTICK)
_glfwInitJoysticksLinux, _glfwInitJoysticksLinux,
_glfwTerminateJoysticksLinux, _glfwTerminateJoysticksLinux,
_glfwPollJoystickLinux, _glfwPollJoystickLinux,

View File

@ -89,7 +89,7 @@ static GLFWbool waitForAnyEvent(double* timeout)
{ _glfw.x11.emptyEventPipe[0], POLLIN } { _glfw.x11.emptyEventPipe[0], POLLIN }
}; };
#if defined(_GLFW_LINUX_JOYSTICK) #if defined(GLFW_BUILD_LINUX_JOYSTICK)
if (_glfw.joysticksInitialized) if (_glfw.joysticksInitialized)
fds[count++] = (struct pollfd) { _glfw.linjs.inotify, POLLIN }; fds[count++] = (struct pollfd) { _glfw.linjs.inotify, POLLIN };
#endif #endif
@ -2806,7 +2806,7 @@ void _glfwPollEventsX11(void)
{ {
drainEmptyEvents(); drainEmptyEvents();
#if defined(_GLFW_LINUX_JOYSTICK) #if defined(GLFW_BUILD_LINUX_JOYSTICK)
if (_glfw.joysticksInitialized) if (_glfw.joysticksInitialized)
_glfwDetectJoystickConnectionLinux(); _glfwDetectJoystickConnectionLinux();
#endif #endif