mirror of
https://github.com/glfw/glfw.git
synced 2024-11-24 21:54:35 +00:00
Wayland: Add initial support for libdecor
This is partly based on the implementation of libdecor support in PR #1693 by @ christianrauch. Where available, the libdecor library is loaded at init and becomes the preferred method for window decorations. On compositors that support XDG decorations, libdecor in turn uses those. If not, libdecor has a plug-in archtecture and may load additional libraries to either use compositor-specific decorations or draw its own. If necessary, support for libdecor can be disabled with the GLFW_WAYLAND_LIBDECOR init hint. This is mostly in case some part of the dynamic loading or duplication of header material added here turns out to cause problems with future versions of libdecor-0.so.0. Fixes #1639 Closes #1693 Related to #1725
This commit is contained in:
parent
cd466cf9fd
commit
fbdb53b9ca
@ -311,6 +311,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)
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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,
|
||||||
|
@ -379,6 +379,9 @@ struct _GLFWinitconfig
|
|||||||
struct {
|
struct {
|
||||||
GLFWbool xcbVulkanSurface;
|
GLFWbool xcbVulkanSurface;
|
||||||
} x11;
|
} x11;
|
||||||
|
struct {
|
||||||
|
int libdecorMode;
|
||||||
|
} wl;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Window configuration
|
// Window configuration
|
||||||
|
119
src/wl_init.c
119
src/wl_init.c
@ -202,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)
|
||||||
@ -652,6 +666,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, ®istryListener, NULL);
|
wl_registry_add_listener(_glfw.wl.registry, ®istryListener, NULL);
|
||||||
|
|
||||||
@ -671,6 +772,15 @@ 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 (wl_seat_get_version(_glfw.wl.seat) >= WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION)
|
if (wl_seat_get_version(_glfw.wl.seat) >= WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION)
|
||||||
{
|
{
|
||||||
@ -712,6 +822,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);
|
||||||
|
@ -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
|
||||||
@ -86,6 +88,7 @@ typedef struct wl_proxy* (* PFN_wl_proxy_marshal_flags)(struct wl_proxy*,uint32_
|
|||||||
#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
|
||||||
@ -202,6 +205,122 @@ 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
|
||||||
{
|
{
|
||||||
GLFW_MAIN_WINDOW,
|
GLFW_MAIN_WINDOW,
|
||||||
@ -264,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;
|
||||||
|
|
||||||
@ -422,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
|
||||||
|
297
src/wl_window.c
297
src/wl_window.c
@ -447,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);
|
||||||
@ -463,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);
|
||||||
@ -611,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);
|
||||||
@ -707,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);
|
||||||
|
|
||||||
@ -724,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;
|
||||||
@ -891,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)
|
||||||
@ -919,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;
|
||||||
@ -964,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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1891,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1939,6 +2153,13 @@ void _glfwSetWindowSizeWayland(_GLFWwindow* window, int width, int height)
|
|||||||
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)
|
if (window->wl.visible)
|
||||||
_glfwInputWindowDamage(window);
|
_glfwInputWindowDamage(window);
|
||||||
}
|
}
|
||||||
@ -1948,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;
|
||||||
@ -2001,6 +2235,13 @@ void _glfwSetWindowAspectRatioWayland(_GLFWwindow* window, int numer, int denom)
|
|||||||
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);
|
||||||
|
}
|
||||||
|
|
||||||
_glfwInputWindowSize(window, width, height);
|
_glfwInputWindowSize(window, width, height);
|
||||||
|
|
||||||
if (window->wl.visible)
|
if (window->wl.visible)
|
||||||
@ -2045,7 +2286,9 @@ void _glfwGetWindowContentScaleWayland(_GLFWwindow* window,
|
|||||||
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2062,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;
|
||||||
@ -2072,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;
|
||||||
@ -2080,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
|
||||||
@ -2171,15 +2418,35 @@ GLFWbool _glfwFramebufferTransparentWayland(_GLFWwindow* window)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _glfwSetWindowResizableWayland(_GLFWwindow* window, GLFWbool enabled)
|
void _glfwSetWindowResizableWayland(_GLFWwindow* window, GLFWbool enabled)
|
||||||
|
{
|
||||||
|
if (window->wl.libdecor.frame)
|
||||||
|
{
|
||||||
|
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
|
// TODO
|
||||||
_glfwInputError(GLFW_FEATURE_UNIMPLEMENTED,
|
_glfwInputError(GLFW_FEATURE_UNIMPLEMENTED,
|
||||||
"Wayland: Window attribute setting not implemented yet");
|
"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;
|
||||||
|
|
||||||
@ -2190,7 +2457,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);
|
||||||
|
Loading…
Reference in New Issue
Block a user