diff --git a/README.md b/README.md
index 1c7ced36..96e76813 100644
--- a/README.md
+++ b/README.md
@@ -120,6 +120,7 @@ information on what to include when reporting a bug.
## Changelog since 3.4
+ - [Wayland] Feature: Added wlr layer shell support for widgets creation
- Added `GLFW_UNLIMITED_MOUSE_BUTTONS` input mode that allows mouse buttons beyond
the limit of the mouse button tokens to be reported (#2423)
- Added `glfwGetEGLConfig` function to query the `EGLConfig` of a window (#2045)
diff --git a/deps/wayland/wlr-layer-shell-unstable-v1.xml b/deps/wayland/wlr-layer-shell-unstable-v1.xml
new file mode 100644
index 00000000..6dfc3567
--- /dev/null
+++ b/deps/wayland/wlr-layer-shell-unstable-v1.xml
@@ -0,0 +1,391 @@
+
+
+
+ Copyright © 2017 Drew DeVault
+
+ Permission to use, copy, modify, distribute, and sell this
+ software and its documentation for any purpose is hereby granted
+ without fee, provided that the above copyright notice appear in
+ all copies and that both that copyright notice and this permission
+ notice appear in supporting documentation, and that the name of
+ the copyright holders not be used in advertising or publicity
+ pertaining to distribution of the software without specific,
+ written prior permission. The copyright holders make no
+ representations about the suitability of this software for any
+ purpose. It is provided "as is" without express or implied
+ warranty.
+
+ THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+ THIS SOFTWARE.
+
+
+
+
+ Clients can use this interface to assign the surface_layer role to
+ wl_surfaces. Such surfaces are assigned to a "layer" of the output and
+ rendered with a defined z-depth respective to each other. They may also be
+ anchored to the edges and corners of a screen and specify input handling
+ semantics. This interface should be suitable for the implementation of
+ many desktop shell components, and a broad number of other applications
+ that interact with the desktop.
+
+
+
+
+ Create a layer surface for an existing surface. This assigns the role of
+ layer_surface, or raises a protocol error if another role is already
+ assigned.
+
+ Creating a layer surface from a wl_surface which has a buffer attached
+ or committed is a client error, and any attempts by a client to attach
+ or manipulate a buffer prior to the first layer_surface.configure call
+ must also be treated as errors.
+
+ After creating a layer_surface object and setting it up, the client
+ must perform an initial commit without any buffer attached.
+ The compositor will reply with a layer_surface.configure event.
+ The client must acknowledge it and is then allowed to attach a buffer
+ to map the surface.
+
+ You may pass NULL for output to allow the compositor to decide which
+ output to use. Generally this will be the one that the user most
+ recently interacted with.
+
+ Clients can specify a namespace that defines the purpose of the layer
+ surface.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ These values indicate which layers a surface can be rendered in. They
+ are ordered by z depth, bottom-most first. Traditional shell surfaces
+ will typically be rendered between the bottom and top layers.
+ Fullscreen shell surfaces are typically rendered at the top layer.
+ Multiple surfaces can share a single layer, and ordering within a
+ single layer is undefined.
+
+
+
+
+
+
+
+
+
+
+
+
+ This request indicates that the client will not use the layer_shell
+ object any more. Objects that have been created through this instance
+ are not affected.
+
+
+
+
+
+
+ An interface that may be implemented by a wl_surface, for surfaces that
+ are designed to be rendered as a layer of a stacked desktop-like
+ environment.
+
+ Layer surface state (layer, size, anchor, exclusive zone,
+ margin, interactivity) is double-buffered, and will be applied at the
+ time wl_surface.commit of the corresponding wl_surface is called.
+
+ Attaching a null buffer to a layer surface unmaps it.
+
+ Unmapping a layer_surface means that the surface cannot be shown by the
+ compositor until it is explicitly mapped again. The layer_surface
+ returns to the state it had right after layer_shell.get_layer_surface.
+ The client can re-map the surface by performing a commit without any
+ buffer attached, waiting for a configure event and handling it as usual.
+
+
+
+
+ Sets the size of the surface in surface-local coordinates. The
+ compositor will display the surface centered with respect to its
+ anchors.
+
+ If you pass 0 for either value, the compositor will assign it and
+ inform you of the assignment in the configure event. You must set your
+ anchor to opposite edges in the dimensions you omit; not doing so is a
+ protocol error. Both values are 0 by default.
+
+ Size is double-buffered, see wl_surface.commit.
+
+
+
+
+
+
+
+ Requests that the compositor anchor the surface to the specified edges
+ and corners. If two orthogonal edges are specified (e.g. 'top' and
+ 'left'), then the anchor point will be the intersection of the edges
+ (e.g. the top left corner of the output); otherwise the anchor point
+ will be centered on that edge, or in the center if none is specified.
+
+ Anchor is double-buffered, see wl_surface.commit.
+
+
+
+
+
+
+ Requests that the compositor avoids occluding an area with other
+ surfaces. The compositor's use of this information is
+ implementation-dependent - do not assume that this region will not
+ actually be occluded.
+
+ A positive value is only meaningful if the surface is anchored to one
+ edge or an edge and both perpendicular edges. If the surface is not
+ anchored, anchored to only two perpendicular edges (a corner), anchored
+ to only two parallel edges or anchored to all edges, a positive value
+ will be treated the same as zero.
+
+ A positive zone is the distance from the edge in surface-local
+ coordinates to consider exclusive.
+
+ Surfaces that do not wish to have an exclusive zone may instead specify
+ how they should interact with surfaces that do. If set to zero, the
+ surface indicates that it would like to be moved to avoid occluding
+ surfaces with a positive exclusive zone. If set to -1, the surface
+ indicates that it would not like to be moved to accommodate for other
+ surfaces, and the compositor should extend it all the way to the edges
+ it is anchored to.
+
+ For example, a panel might set its exclusive zone to 10, so that
+ maximized shell surfaces are not shown on top of it. A notification
+ might set its exclusive zone to 0, so that it is moved to avoid
+ occluding the panel, but shell surfaces are shown underneath it. A
+ wallpaper or lock screen might set their exclusive zone to -1, so that
+ they stretch below or over the panel.
+
+ The default value is 0.
+
+ Exclusive zone is double-buffered, see wl_surface.commit.
+
+
+
+
+
+
+ Requests that the surface be placed some distance away from the anchor
+ point on the output, in surface-local coordinates. Setting this value
+ for edges you are not anchored to has no effect.
+
+ The exclusive zone includes the margin.
+
+ Margin is double-buffered, see wl_surface.commit.
+
+
+
+
+
+
+
+
+
+ Types of keyboard interaction possible for layer shell surfaces. The
+ rationale for this is twofold: (1) some applications are not interested
+ in keyboard events and not allowing them to be focused can improve the
+ desktop experience; (2) some applications will want to take exclusive
+ keyboard focus.
+
+
+
+
+ This value indicates that this surface is not interested in keyboard
+ events and the compositor should never assign it the keyboard focus.
+
+ This is the default value, set for newly created layer shell surfaces.
+
+ This is useful for e.g. desktop widgets that display information or
+ only have interaction with non-keyboard input devices.
+
+
+
+
+ Request exclusive keyboard focus if this surface is above the shell surface layer.
+
+ For the top and overlay layers, the seat will always give
+ exclusive keyboard focus to the top-most layer which has keyboard
+ interactivity set to exclusive. If this layer contains multiple
+ surfaces with keyboard interactivity set to exclusive, the compositor
+ determines the one receiving keyboard events in an implementation-
+ defined manner. In this case, no guarantee is made when this surface
+ will receive keyboard focus (if ever).
+
+ For the bottom and background layers, the compositor is allowed to use
+ normal focus semantics.
+
+ This setting is mainly intended for applications that need to ensure
+ they receive all keyboard events, such as a lock screen or a password
+ prompt.
+
+
+
+
+ This requests the compositor to allow this surface to be focused and
+ unfocused by the user in an implementation-defined manner. The user
+ should be able to unfocus this surface even regardless of the layer
+ it is on.
+
+ Typically, the compositor will want to use its normal mechanism to
+ manage keyboard focus between layer shell surfaces with this setting
+ and regular toplevels on the desktop layer (e.g. click to focus).
+ Nevertheless, it is possible for a compositor to require a special
+ interaction to focus or unfocus layer shell surfaces (e.g. requiring
+ a click even if focus follows the mouse normally, or providing a
+ keybinding to switch focus between layers).
+
+ This setting is mainly intended for desktop shell components (e.g.
+ panels) that allow keyboard interaction. Using this option can allow
+ implementing a desktop shell that can be fully usable without the
+ mouse.
+
+
+
+
+
+
+ Set how keyboard events are delivered to this surface. By default,
+ layer shell surfaces do not receive keyboard events; this request can
+ be used to change this.
+
+ This setting is inherited by child surfaces set by the get_popup
+ request.
+
+ Layer surfaces receive pointer, touch, and tablet events normally. If
+ you do not want to receive them, set the input region on your surface
+ to an empty region.
+
+ Keyboard interactivity is double-buffered, see wl_surface.commit.
+
+
+
+
+
+
+ This assigns an xdg_popup's parent to this layer_surface. This popup
+ should have been created via xdg_surface::get_popup with the parent set
+ to NULL, and this request must be invoked before committing the popup's
+ initial state.
+
+ See the documentation of xdg_popup for more details about what an
+ xdg_popup is and how it is used.
+
+
+
+
+
+
+ When a configure event is received, if a client commits the
+ surface in response to the configure event, then the client
+ must make an ack_configure request sometime before the commit
+ request, passing along the serial of the configure event.
+
+ If the client receives multiple configure events before it
+ can respond to one, it only has to ack the last configure event.
+
+ A client is not required to commit immediately after sending
+ an ack_configure request - it may even ack_configure several times
+ before its next surface commit.
+
+ A client may send multiple ack_configure requests before committing, but
+ only the last request sent before a commit indicates which configure
+ event the client really is responding to.
+
+
+
+
+
+
+ This request destroys the layer surface.
+
+
+
+
+
+ The configure event asks the client to resize its surface.
+
+ Clients should arrange their surface for the new states, and then send
+ an ack_configure request with the serial sent in this configure event at
+ some point before committing the new surface.
+
+ The client is free to dismiss all but the last configure event it
+ received.
+
+ The width and height arguments specify the size of the window in
+ surface-local coordinates.
+
+ The size is a hint, in the sense that the client is free to ignore it if
+ it doesn't resize, pick a smaller size (to satisfy aspect ratio or
+ resize in steps of NxM pixels). If the client picks a smaller size and
+ is anchored to two opposite anchors (e.g. 'top' and 'bottom'), the
+ surface will be centered on this axis.
+
+ If the width or height arguments are zero, it means the client should
+ decide its own window dimension.
+
+
+
+
+
+
+
+
+ The closed event is sent by the compositor when the surface will no
+ longer be shown. The output may have been destroyed or the user may
+ have asked for it to be removed. Further changes to the surface will be
+ ignored. The client should destroy the resource after receiving this
+ event, and create a new surface if they so choose.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Change the layer that the surface is rendered on.
+
+ Layer is double-buffered, see wl_surface.commit.
+
+
+
+
+
+
diff --git a/docs/news.md b/docs/news.md
index 06a930d5..2dd9d977 100644
--- a/docs/news.md
+++ b/docs/news.md
@@ -5,6 +5,16 @@
## New features {#features}
+### [ZWLR Layer Shell support for Wayland](https://wayland.app/protocols/wlr-layer-shell-unstable-v1)
+
+Create surfaces that are layers of the desktop
+
+Such surfaces are assigned to a "layer" of the output and rendered with
+a defined z-depth respective to each other. They may also be anchored to the
+edges and corners of a screen and specify input handling semantics.
+This interface should be suitable for the implementation of many desktop shell
+components, and a broad number of other applications that interact with the desktop.
+
### Unlimited mouse buttons {#unlimited_mouse_buttons}
GLFW now has an input mode which allows an unlimited number of mouse buttons to
diff --git a/docs/window.md b/docs/window.md
index 2140f097..4f467aa3 100644
--- a/docs/window.md
+++ b/docs/window.md
@@ -518,6 +518,14 @@ __GLFW_WAYLAND_APP_ID__ specifies the Wayland app_id for a window, used
by window managers to identify types of windows. This is set with
@ref glfwWindowHintString.
+@anchor GLFW_WAYLAND_USE_ZWLR_hint
+__GLFW_WAYLAND_USE_ZWLR__ Try to utilize
+[wlr layers system](https://wayland.app/protocols/wlr-layer-shell-unstable-v1)
+from your compositor.
+This is set by @ref glfwWindowHint with [special init layer](@ref GLFW_WAYLAND_USE_ZWLR).
+If success, you can control layer behavior with
+[](@ref glfwWaylandZwlrSetLayer) api.
+Example available [here](https://github.com/glfw/glfw/blob/master/examples/wayland-widget.c).
#### X11 specific window hints {#window_hints_x11}
@@ -577,10 +585,10 @@ GLFW_WIN32_KEYBOARD_MENU | `GLFW_FALSE` | `GLFW_TRUE` or `GL
GLFW_WIN32_SHOWDEFAULT | `GLFW_FALSE` | `GLFW_TRUE` or `GLFW_FALSE`
GLFW_COCOA_FRAME_NAME | `""` | A UTF-8 encoded frame autosave name
GLFW_COCOA_GRAPHICS_SWITCHING | `GLFW_FALSE` | `GLFW_TRUE` or `GLFW_FALSE`
-GLFW_WAYLAND_APP_ID | `""` | An ASCII encoded Wayland `app_id` name
GLFW_X11_CLASS_NAME | `""` | An ASCII encoded `WM_CLASS` class name
GLFW_X11_INSTANCE_NAME | `""` | An ASCII encoded `WM_CLASS` instance name
-
+GLFW_WAYLAND_APP_ID | `""` | An ASCII encoded Wayland `app_id` name
+GLFW_WAYLAND_USE_ZWLR | 0 | `GLFW_WAYLAND_ZWLR_LAYER_BACKGROUD`, `GLFW_WAYLAND_ZWLR_LAYER_BOTTOM`, `GLFW_WAYLAND_ZWLR_LAYER_TOP` or `GLFW_WAYLAND_ZWLR_LAYER_OVERLAY`
## Window event processing {#window_events}
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
index e7a03797..d9f32739 100644
--- a/examples/CMakeLists.txt
+++ b/examples/CMakeLists.txt
@@ -36,6 +36,10 @@ add_executable(triangle-opengl WIN32 MACOSX_BUNDLE triangle-opengl.c ${ICON} ${G
add_executable(triangle-opengles WIN32 MACOSX_BUNDLE triangle-opengles.c ${ICON} ${GLAD_GLES2})
add_executable(wave WIN32 MACOSX_BUNDLE wave.c ${ICON} ${GLAD_GL})
add_executable(windows WIN32 MACOSX_BUNDLE windows.c ${ICON} ${GLAD_GL})
+if (Wayland_FOUND)
+ add_executable(wayland-widget wayland-widget.c ${ICON} ${GLAD_GL})
+endif()
+
target_link_libraries(particles Threads::Threads)
if (RT_LIBRARY)
diff --git a/examples/wayland-widget.c b/examples/wayland-widget.c
new file mode 100644
index 00000000..00a5659f
--- /dev/null
+++ b/examples/wayland-widget.c
@@ -0,0 +1,128 @@
+
+#define GLAD_GL_IMPLEMENTATION
+#include
+
+#define GLFW_INCLUDE_NONE
+#define GLFW_EXPOSE_NATIVE_WAYLAND
+#include
+#include
+
+
+#include
+#include
+#include
+
+
+#define WIN_HEIGHT 150
+
+
+static void GLFW_DebugCallback(int err_code, const char* description)
+{
+ printf("GLFW error: %s\n", description);
+}
+
+
+static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
+{
+ static bool onTopLayer = true;
+ static bool onTopAnchor = true;
+
+ if (action == GLFW_PRESS)
+ {
+ printf("Grabbing...\n");
+ switch (key)
+ {
+ case GLFW_KEY_RIGHT:
+ case GLFW_KEY_LEFT :
+ {
+ onTopLayer = !onTopLayer;
+
+ if (onTopLayer)
+ {
+ printf("Send to top\n");
+ glfwWaylandZwlrSetLayer(window, GLFW_WAYLAND_ZWLR_LAYER_TOP);
+ }
+ else
+ {
+ printf("Send to bottom\n");
+ glfwWaylandZwlrSetLayer(window, GLFW_WAYLAND_ZWLR_LAYER_BOTTOM);
+ }
+
+ break;
+ }
+
+ case GLFW_KEY_UP:
+ case GLFW_KEY_DOWN:
+ {
+ onTopAnchor = !onTopAnchor;
+
+ if (onTopAnchor)
+ {
+ printf("Stick to top\n");
+ glfwWaylandZwlrSetAnchor(window, GLFW_WAYLAND_ZWLR_ANCHOR_TOP);
+
+ }
+ else
+ {
+ printf("Stick to bottom\n");
+ glfwWaylandZwlrSetAnchor(window, GLFW_WAYLAND_ZWLR_ANCHOR_BOTTOM);
+ }
+ break;
+ }
+ }
+ }
+}
+
+
+void mouse_button_callback(GLFWwindow* window, int button, int action, int mods)
+{
+ if (action == GLFW_RELEASE)
+ printf("click\n");
+}
+
+
+int main(int argc, char** argv)
+{
+ glfwSetErrorCallback(GLFW_DebugCallback);
+
+ if (!glfwInit()) return 1;
+
+ glfwWindowHint(GLFW_WAYLAND_USE_ZWLR, GLFW_WAYLAND_ZWLR_LAYER_TOP);
+
+ int monitorX_pos, monitorY_pos;
+ int monitorWidth, monitorHeight;
+ GLFWmonitor* primary_monitor = glfwGetPrimaryMonitor();
+ glfwGetMonitorWorkarea(primary_monitor, &monitorX_pos, &monitorY_pos, &monitorWidth, &monitorHeight);
+
+ // v-- 0 not allowed by glfw api, for avoiding mess with internal api, you are forced..
+ // v ..to request monitor size and manually handle window size
+ GLFWwindow* window = glfwCreateWindow(300, WIN_HEIGHT, "Don't Care", NULL, NULL);
+ if (!window) return 1;
+
+ glfwSetWindowSize(window, monitorWidth, WIN_HEIGHT); // just testing
+ //glfwWaylandZwlrSetExclusiveZone(window, WIN_HEIGHT + 50); // try to play with
+ //glfwWaylandZwlrSetMargin(window, 10, 10, 10, 10);
+
+ glfwMakeContextCurrent (window);
+ gladLoadGL(glfwGetProcAddress);
+ glfwSetMouseButtonCallback(window, mouse_button_callback );
+ //glfwSetCursorPosCallback (window, cursor_position_callback);
+ glfwSetKeyCallback (window, key_callback );
+ //glfwSetWindowFocusCallback(window, window_focus_callback) ;
+
+
+ glClearColor(0.3f, 0.2f, 0.3f, 1.0f);
+
+ while (!glfwWindowShouldClose(window))
+ {
+ glfwSwapBuffers(window);
+ glfwPollEvents();
+
+ glClear(GL_COLOR_BUFFER_BIT);
+ }
+
+ return 0;
+}
+
+
+
diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h
index 3ce1c019..fd7e7215 100644
--- a/include/GLFW/glfw3.h
+++ b/include/GLFW/glfw3.h
@@ -1135,6 +1135,27 @@ extern "C" {
* Allows specification of the Wayland app_id.
*/
#define GLFW_WAYLAND_APP_ID 0x00026001
+
+#define GLFW_WAYLAND_ZWLR_LAYER_BACKGROUD 0x00026002
+#define GLFW_WAYLAND_ZWLR_LAYER_BOTTOM 0x00026003
+#define GLFW_WAYLAND_ZWLR_LAYER_TOP 0x00026004
+#define GLFW_WAYLAND_ZWLR_LAYER_OVERLAY 0x00026005
+
+#define GLFW_WAYLAND_ZWLR_ANCHOR_TOP 0x1
+#define GLFW_WAYLAND_ZWLR_ANCHOR_BOTTOM 0x2
+#define GLFW_WAYLAND_ZWLR_ANCHOR_LEFT 0x4
+#define GLFW_WAYLAND_ZWLR_ANCHOR_RIGHT 0x8
+/*! @brief Wayland specific
+ * [window hint](@ref GLFW_WAYLAND_USE_ZWLR_hint).
+ *
+ * Available options are:
+ * - GLFW_WAYLAND_ZWLR_BACKGROUD
+ * - GLFW_WAYLAND_ZWLR_BOTTOM
+ * - GLFW_WAYLAND_ZWLR_TOP
+ * - GLFW_WAYLAND_ZWLR_OVERLAY
+ */
+#define GLFW_WAYLAND_USE_ZWLR 0x00026010
+
/*! @} */
#define GLFW_NO_API 0
diff --git a/include/GLFW/glfw3native.h b/include/GLFW/glfw3native.h
index 8db2cfa3..03c0c489 100644
--- a/include/GLFW/glfw3native.h
+++ b/include/GLFW/glfw3native.h
@@ -554,6 +554,81 @@ GLFWAPI struct wl_output* glfwGetWaylandMonitor(GLFWmonitor* monitor);
* @ingroup native
*/
GLFWAPI struct wl_surface* glfwGetWaylandWindow(GLFWwindow* window);
+
+/*! @brief Change the layer that the surface is rendered on.
+ *
+ * @errors Possible errors include @ref GLFW_FEATURE_UNAVAILABLE and @ref
+ * GLFW_PLATFORM_UNAVAILABLE and @ref GLFW_INVALID_ENUM.
+ *
+ * @param[in] layer GLFW_WAYLAND_ZWLR_LAYER_BACKGROUD,
+ * GLFW_WAYLAND_ZWLR_LAYER_BOTTOM,
+ * GLFW_WAYLAND_ZWLR_LAYER_TOP,
+ * GLFW_WAYLAND_ZWLR_LAYER_OVERLAY.
+
+ * @thread_safety This function should be called from main thread.
+ *
+ * @since Added in version 3.5.
+ *
+ * @ingroup native
+ */
+GLFWAPI void glfwWaylandZwlrSetLayer(GLFWwindow* window, int layer);
+
+/*! @brief Configures the anchor point of the surface.
+ *
+ * Requests that the compositor anchor the surface to the specified
+ * edges and corners. If two orthogonal edges are specified
+ * (e.g. 'top' and 'left'), then the anchor point will be the
+ * intersection of the edges (e.g. the top left corner of the output);
+ * otherwise the anchor point will be centered on that edge,
+ * or in the center if none is specified.
+ *
+ * @param[in] anchor GLFW_WAYLAND_ZWLR_ANCHOR_TOP |
+ * GLFW_WAYLAND_ZWLR_ANCHOR_BOTTOM |
+ * GLFW_WAYLAND_ZWLR_ANCHOR_LEFT |
+ * GLFW_WAYLAND_ZWLR_ANCHOR_RIGHT
+ *
+ * @errors Possible errors include @ref GLFW_FEATURE_UNAVAILABLE and @ref
+ * GLFW_PLATFORM_UNAVAILABLE. Viewport is centered if you send incorrect anchor.
+ *
+ * @thread_safety This function should be called from main thread.
+ *
+ * @since Added in version 3.5.
+ *
+ * @ingroup native
+ */
+GLFWAPI void glfwWaylandZwlrSetAnchor(GLFWwindow* window, int anchor);
+
+/*! @brief Requests that the compositor avoids occluding an area with other surfaces.
+ *
+ * @note The compositor's use of this information is implementation-dependent.
+ * Do not assume that this region will not actually be occluded.
+ *
+ * @errors Possible errors include @ref GLFW_FEATURE_UNAVAILABLE and @ref
+ * GLFW_PLATFORM_UNAVAILABLE.
+ *
+ * @thread_safety This function should be called from main thread.
+ *
+ * @since Added in version 3.5.
+ *
+ * @ingroup native
+ */
+GLFWAPI void glfwWaylandZwlrSetExclusiveZone(GLFWwindow* window, int zone);
+
+/*! @brief Requests that the surface be placed some distance away from the
+ * anchor point on the output, in surface-local coordinates. Setting this
+ * value for edges you are not anchored to has no effect.
+ * The exclusive zone includes the margin.
+ *
+ * @errors Possible errors include @ref GLFW_FEATURE_UNAVAILABLE and @ref
+ * GLFW_PLATFORM_UNAVAILABLE.
+ *
+ * @thread_safety This function should be called from main thread.
+ *
+ * @since Added in version 3.5.
+ *
+ * @ingroup native
+ */
+GLFWAPI void glfwWaylandZwlrSetMargin(GLFWwindow* window, int top, int right, int bottom, int left);
#endif
#if defined(GLFW_EXPOSE_NATIVE_EGL)
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 2cbe8a73..eb63aebd 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -105,6 +105,7 @@ if (GLFW_BUILD_WAYLAND)
generate_wayland_protocol("fractional-scale-v1.xml")
generate_wayland_protocol("xdg-activation-v1.xml")
generate_wayland_protocol("xdg-decoration-unstable-v1.xml")
+ generate_wayland_protocol("wlr-layer-shell-unstable-v1.xml")
endif()
if (WIN32 AND GLFW_BUILD_SHARED_LIBRARY)
diff --git a/src/init.c b/src/init.c
index dbd5a900..51cdc24d 100644
--- a/src/init.c
+++ b/src/init.c
@@ -33,7 +33,6 @@
#include
#include
-
// NOTE: The global variables below comprise all mutable global data in GLFW
// Any other mutable global variable is a bug
diff --git a/src/internal.h b/src/internal.h
index de703740..0133ee24 100644
--- a/src/internal.h
+++ b/src/internal.h
@@ -427,6 +427,7 @@ struct _GLFWwndconfig
} win32;
struct {
char appId[256];
+ GLFWbool useZWLR;
} wl;
};
diff --git a/src/window.c b/src/window.c
index 3a3b66df..3f99b2ed 100644
--- a/src/window.c
+++ b/src/window.c
@@ -381,6 +381,9 @@ GLFWAPI void glfwWindowHint(int hint, int value)
case GLFW_COCOA_GRAPHICS_SWITCHING:
_glfw.hints.context.nsgl.offline = value ? GLFW_TRUE : GLFW_FALSE;
return;
+ case GLFW_WAYLAND_USE_ZWLR:
+ _glfw.hints.window.wl.useZWLR = value;
+ return;
case GLFW_SCALE_TO_MONITOR:
_glfw.hints.window.scaleToMonitor = value ? GLFW_TRUE : GLFW_FALSE;
return;
diff --git a/src/wl_init.c b/src/wl_init.c
index ef9e4503..942152b7 100644
--- a/src/wl_init.c
+++ b/src/wl_init.c
@@ -49,6 +49,7 @@
#include "fractional-scale-v1-client-protocol.h"
#include "xdg-activation-v1-client-protocol.h"
#include "idle-inhibit-unstable-v1-client-protocol.h"
+#include "wlr-layer-shell-unstable-v1-client-protocol.h"
// NOTE: Versions of wayland-scanner prior to 1.17.91 named every global array of
// wl_interface pointers 'types', making it impossible to combine several unmodified
@@ -91,6 +92,11 @@
#include "idle-inhibit-unstable-v1-client-protocol-code.h"
#undef types
+#define types _glfw_zwlr_layer_shell_types
+#include "wlr-layer-shell-unstable-v1-client-protocol-code.h"
+#undef types
+
+
static void wmBaseHandlePing(void* userData,
struct xdg_wm_base* wmBase,
uint32_t serial)
@@ -208,6 +214,13 @@ static void registryHandleGlobal(void* userData,
&wp_fractional_scale_manager_v1_interface,
1);
}
+ else if (strcmp(interface, "zwlr_layer_shell_v1") == 0)
+ {
+ _glfw.wl.zwlrLayerShell =
+ wl_registry_bind(registry, name,
+ &zwlr_layer_shell_v1_interface,
+ 5); // use the latest version, because why not? (since 2017)
+ }
}
static void registryHandleGlobalRemove(void* userData,
@@ -395,6 +408,8 @@ static void createKeyTables(void)
}
}
+
+
static GLFWbool loadCursorTheme(void)
{
int cursorSize = 16;
@@ -424,6 +439,7 @@ static GLFWbool loadCursorTheme(void)
_glfw.wl.cursorSurface = wl_compositor_create_surface(_glfw.wl.compositor);
_glfw.wl.cursorTimerfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK);
+
return GLFW_TRUE;
}
@@ -948,6 +964,8 @@ void _glfwTerminateWayland(void)
_glfw_free(_glfw.wl.offers);
+ if(_glfw.wl.zwlrLayerShell)
+ zwlr_layer_shell_v1_destroy(_glfw.wl.zwlrLayerShell);
if (_glfw.wl.cursorSurface)
wl_surface_destroy(_glfw.wl.cursorSurface);
if (_glfw.wl.subcompositor)
diff --git a/src/wl_platform.h b/src/wl_platform.h
index c3e45693..33d74698 100644
--- a/src/wl_platform.h
+++ b/src/wl_platform.h
@@ -130,6 +130,7 @@ struct wl_output;
#define xdg_activation_token_v1_interface _glfw_xdg_activation_token_v1_interface
#define wl_surface_interface _glfw_wl_surface_interface
#define wp_fractional_scale_v1_interface _glfw_wp_fractional_scale_v1_interface
+#define zwlr_layer_shell_v1_interface _glfw_zwlr_layer_shell_v1
#define GLFW_WAYLAND_WINDOW_STATE _GLFWwindowWayland wl;
#define GLFW_WAYLAND_LIBRARY_WINDOW_STATE _GLFWlibraryWayland wl;
@@ -381,6 +382,11 @@ typedef struct _GLFWwindowWayland
uint32_t decorationMode;
} xdg;
+ struct {
+ struct zwlr_layer_surface_v1* surface;
+ } zwlr;
+
+
struct {
struct libdecor_frame* frame;
} libdecor;
@@ -440,6 +446,7 @@ typedef struct _GLFWlibraryWayland
struct zwp_idle_inhibit_manager_v1* idleInhibitManager;
struct xdg_activation_v1* activationManager;
struct wp_fractional_scale_manager_v1* fractionalScaleManager;
+ struct zwlr_layer_shell_v1* zwlrLayerShell;
_GLFWofferWayland* offers;
unsigned int offerCount;
diff --git a/src/wl_window.c b/src/wl_window.c
index 4220d17e..2aa2d6c4 100644
--- a/src/wl_window.c
+++ b/src/wl_window.c
@@ -51,6 +51,7 @@
#include "xdg-activation-v1-client-protocol.h"
#include "idle-inhibit-unstable-v1-client-protocol.h"
#include "fractional-scale-v1-client-protocol.h"
+#include "wlr-layer-shell-unstable-v1-client-protocol.h"
#define GLFW_BORDER_SIZE 4
#define GLFW_CAPTION_HEIGHT 24
@@ -495,6 +496,9 @@ static GLFWbool resizeWindow(_GLFWwindow* window, int width, int height)
window->wl.width = width;
window->wl.height = height;
+ if (window->wl.zwlr.surface)
+ zwlr_layer_surface_v1_set_size(window->wl.zwlr.surface, width, height);
+
resizeFramebuffer(window);
if (window->wl.scalingViewport)
@@ -1130,8 +1134,76 @@ static GLFWbool createXdgShellObjects(_GLFWwindow* window)
return GLFW_TRUE;
}
+static void zwlrSurfaceConfigure(void *data,
+ struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1,
+ uint32_t serial,
+ uint32_t width,
+ uint32_t height)
+{
+ _GLFWwindow* window = data;
+
+ window->wl.visible = GLFW_TRUE; // I'm not sure this belong here, but window not visible without
+ resizeWindow(window, width, height);
+
+ zwlr_layer_surface_v1_ack_configure(zwlr_layer_surface_v1, serial);
+}
+
+static void zwlrSurfaceClose(void *userData,
+ struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1)
+{
+ _GLFWwindow* window = userData;
+ _glfwInputWindowCloseRequest(window);
+
+}
+
+static const struct zwlr_layer_surface_v1_listener zwlrSurfaceListener =
+{
+ .configure = zwlrSurfaceConfigure,
+ .closed = zwlrSurfaceClose
+};
+
+static bool createZwlrShellObjects(_GLFWwindow* window)
+{
+ if (!_glfw.wl.zwlrLayerShell)
+ {
+ _glfwInputError(GLFW_PLATFORM_ERROR,
+ "Wayland: zwlr protocol not supported on this system");
+ return GLFW_FALSE;
+ }
+
+ window->wl.zwlr.surface = zwlr_layer_shell_v1_get_layer_surface(_glfw.wl.zwlrLayerShell,
+ window->wl.surface, NULL, ZWLR_LAYER_SHELL_V1_LAYER_TOP, window->title);
+
+ if (!window->wl.zwlr.surface)
+ {
+ _glfwInputError(GLFW_PLATFORM_ERROR,
+ "Wayland: Failed to create layer surface for window");
+ return GLFW_FALSE;
+ }
+ zwlr_layer_surface_v1_add_listener(window->wl.zwlr.surface, &zwlrSurfaceListener,
+ window);
+
+
+ zwlr_layer_surface_v1_set_anchor(window->wl.zwlr.surface, 0); // center
+ zwlr_layer_surface_v1_set_size(window->wl.zwlr.surface,
+ window->wl.fbWidth, window->wl.fbHeight);
+
+ glfwWaylandZwlrSetLayer((GLFWwindow*)window, _glfw.hints.window.wl.useZWLR);
+
+ wl_surface_commit(window->wl.surface);
+ wl_display_roundtrip(_glfw.wl.display);
+
+ return GLFW_TRUE;
+}
+
static GLFWbool createShellObjects(_GLFWwindow* window)
{
+ if (_glfw.hints.window.wl.useZWLR)
+ {
+ if (createZwlrShellObjects(window))
+ return GLFW_TRUE;
+ }
+
if (_glfw.wl.libdecor.context)
{
if (createLibdecorFrame(window))
@@ -1157,6 +1229,9 @@ static void destroyShellObjects(_GLFWwindow* window)
if (window->wl.xdg.surface)
xdg_surface_destroy(window->wl.xdg.surface);
+ if (window->wl.zwlr.surface)
+ zwlr_layer_surface_v1_destroy(window->wl.zwlr.surface);
+
window->wl.libdecor.frame = NULL;
window->wl.xdg.decoration = NULL;
window->wl.xdg.decorationMode = 0;
@@ -1545,6 +1620,13 @@ static void pointerHandleEnter(void* userData,
window->wl.cursorPosY = wl_fixed_to_double(sy);
_glfwInputCursorPos(window, window->wl.cursorPosX, window->wl.cursorPosY);
}
+
+ if (window->wl.zwlr.surface)
+ {
+ // mf don't receive keyboard events by default
+ zwlr_layer_surface_v1_set_keyboard_interactivity(window->wl.zwlr.surface,
+ ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_ON_DEMAND);
+ }
}
else
{
@@ -1574,6 +1656,12 @@ static void pointerHandleLeave(void* userData,
_glfw.wl.serial = serial;
_glfw.wl.pointerFocus = NULL;
+ if (window->wl.zwlr.surface) // TODO: find out why wl.hovered not fired
+ {
+ zwlr_layer_surface_v1_set_keyboard_interactivity(window->wl.zwlr.surface,
+ ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE);
+ }
+
if (window->wl.hovered)
{
window->wl.hovered = GLFW_FALSE;
@@ -2653,7 +2741,7 @@ void _glfwSetWindowDecoratedWayland(_GLFWwindow* window, GLFWbool enabled)
void _glfwSetWindowFloatingWayland(_GLFWwindow* window, GLFWbool enabled)
{
_glfwInputError(GLFW_FEATURE_UNAVAILABLE,
- "Wayland: Platform does not support making a window floating");
+ "Wayland: hint GLFW_WAYLAND_USE_ZWLR for layer support");
}
void _glfwSetWindowMousePassthroughWayland(_GLFWwindow* window, GLFWbool enabled)
@@ -3360,5 +3448,111 @@ GLFWAPI struct wl_surface* glfwGetWaylandWindow(GLFWwindow* handle)
return window->wl.surface;
}
+GLFWAPI void glfwWaylandZwlrSetLayer(GLFWwindow* handle, int layer)
+{
+ _GLFW_REQUIRE_INIT();
+
+ if (_glfw.platform.platformID != GLFW_PLATFORM_WAYLAND)
+ {
+ _glfwInputError(GLFW_PLATFORM_UNAVAILABLE,
+ "Wayland: Platform not initialized");
+ return;
+ }
+
+ _GLFWwindow* window = (_GLFWwindow*) handle;
+ if (!(window->wl.zwlr.surface))
+ {
+ _glfwInputError(GLFW_FEATURE_UNAVAILABLE,
+ "Wayland: zwlr not supported or wasn't requested");
+ return;
+
+ }
+
+ switch (layer)
+ {
+ case GLFW_WAYLAND_ZWLR_LAYER_BACKGROUD: layer = ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND; break;
+ case GLFW_WAYLAND_ZWLR_LAYER_BOTTOM: layer = ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM; break;
+ case GLFW_WAYLAND_ZWLR_LAYER_TOP: layer = ZWLR_LAYER_SHELL_V1_LAYER_TOP; break;
+ case GLFW_WAYLAND_ZWLR_LAYER_OVERLAY: layer = ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY; break;
+ default:
+ {
+ _glfwInputError(GLFW_INVALID_ENUM,
+ "Wayland: invalid zwlr layer received");
+ return;
+ }
+ }
+
+ zwlr_layer_surface_v1_set_layer(window->wl.zwlr.surface, layer);
+ if (layer == ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM || layer == ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND)
+ zwlr_layer_surface_v1_set_keyboard_interactivity(window->wl.zwlr.surface,
+ ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE);
+}
+
+GLFWAPI void glfwWaylandZwlrSetAnchor(GLFWwindow* handle, int anchor)
+{
+ _GLFW_REQUIRE_INIT();
+
+ if (_glfw.platform.platformID != GLFW_PLATFORM_WAYLAND)
+ {
+ _glfwInputError(GLFW_PLATFORM_UNAVAILABLE,
+ "Wayland: Platform not initialized");
+ return;
+ }
+
+ _GLFWwindow* window = (_GLFWwindow*) handle;
+ if (!(window->wl.zwlr.surface))
+ {
+ _glfwInputError(GLFW_FEATURE_UNAVAILABLE,
+ "Wayland: zwlr not supported or wasn't requested");
+ return;
+ }
+
+ zwlr_layer_surface_v1_set_anchor(window->wl.zwlr.surface, anchor);
+}
+
+GLFWAPI void glfwWaylandZwlrSetExclusiveZone(GLFWwindow* handle, int zone)
+{
+ _GLFW_REQUIRE_INIT();
+
+ if (_glfw.platform.platformID != GLFW_PLATFORM_WAYLAND)
+ {
+ _glfwInputError(GLFW_PLATFORM_UNAVAILABLE,
+ "Wayland: Platform not initialized");
+ return;
+ }
+
+ _GLFWwindow* window = (_GLFWwindow*) handle;
+ if (!(window->wl.zwlr.surface))
+ {
+ _glfwInputError(GLFW_FEATURE_UNAVAILABLE,
+ "Wayland: zwlr not supported or wasn't requested");
+ return;
+ }
+
+ zwlr_layer_surface_v1_set_exclusive_zone(window->wl.zwlr.surface, zone);
+}
+
+GLFWAPI void glfwWaylandZwlrSetMargin(GLFWwindow* handle, int top, int right, int bottom, int left)
+{
+ _GLFW_REQUIRE_INIT();
+
+ if (_glfw.platform.platformID != GLFW_PLATFORM_WAYLAND)
+ {
+ _glfwInputError(GLFW_PLATFORM_UNAVAILABLE,
+ "Wayland: Platform not initialized");
+ return;
+ }
+
+ _GLFWwindow* window = (_GLFWwindow*) handle;
+ if (!(window->wl.zwlr.surface))
+ {
+ _glfwInputError(GLFW_FEATURE_UNAVAILABLE,
+ "Wayland: zwlr not supported or wasn't requested");
+ return;
+ }
+
+ zwlr_layer_surface_v1_set_margin(window->wl.zwlr.surface, top, right, bottom, left);
+}
+
#endif // _GLFW_WAYLAND