Wayland: Remove wl_shell support

This protocol is part of the core Wayland, but it is pretty badly
designed and is missing quite a few features, and is in the process of
being phased out in compositors.  Its support in GLFW requires
duplicating pretty much every single window management codepath.

This bumps the required compositor versions to the ones which have
implemented xdg-shell, approximately two years ago, which seems sensible
to me.
This commit is contained in:
Emmanuel Gil Peyrot 2019-03-01 18:46:06 +01:00 committed by linkmauve
parent a337c56848
commit 599fb3de34
5 changed files with 40 additions and 229 deletions

View File

@ -104,11 +104,7 @@ has been configured in the compositor.
GLFW uses the [xdg-shell GLFW uses the [xdg-shell
protocol](https://cgit.freedesktop.org/wayland/wayland-protocols/tree/stable/xdg-shell/xdg-shell.xml) protocol](https://cgit.freedesktop.org/wayland/wayland-protocols/tree/stable/xdg-shell/xdg-shell.xml)
to provide better window management. This protocol is part of to provide better window management. This protocol is part of
wayland-protocols 1.12, and mandatory at build time. If the running compositor wayland-protocols 1.12, and mandatory at build time.
does not support this protocol, the older [wl_shell
interface](https://cgit.freedesktop.org/wayland/wayland/tree/protocol/wayland.xml#n972)
will be used instead. This will result in a worse integration with the
desktop, especially on tiling compositors.
GLFW uses the [relative pointer GLFW uses the [relative pointer
protocol](https://cgit.freedesktop.org/wayland/wayland-protocols/tree/unstable/relative-pointer/relative-pointer-unstable-v1.xml) protocol](https://cgit.freedesktop.org/wayland/wayland-protocols/tree/unstable/relative-pointer/relative-pointer-unstable-v1.xml)

View File

@ -3089,8 +3089,8 @@ GLFWAPI void glfwSetWindowOpacity(GLFWwindow* window, float opacity);
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
* GLFW_PLATFORM_ERROR. * GLFW_PLATFORM_ERROR.
* *
* @remark @wayland There is no concept of iconification in wl_shell, this * @remark @wayland Once a window is iconified, @ref glfwRestoreWindow wont
* function will emit @ref GLFW_PLATFORM_ERROR when using this deprecated * be able to restore it. This is a design decision of the xdg-shell
* protocol. * protocol.
* *
* @thread_safety This function must only be called from the main thread. * @thread_safety This function must only be called from the main thread.
@ -3625,9 +3625,6 @@ GLFWAPI GLFWwindowfocusfun glfwSetWindowFocusCallback(GLFWwindow* window, GLFWwi
* *
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
* *
* @remark @wayland The wl_shell protocol has no concept of iconification,
* this callback will never be called when using this deprecated protocol.
*
* @thread_safety This function must only be called from the main thread. * @thread_safety This function must only be called from the main thread.
* *
* @sa @ref window_iconify * @sa @ref window_iconify

View File

@ -237,9 +237,7 @@ static void pointerHandleButton(void* data,
{ {
_GLFWwindow* window = _glfw.wl.pointerFocus; _GLFWwindow* window = _glfw.wl.pointerFocus;
int glfwButton; int glfwButton;
uint32_t edges = XDG_TOPLEVEL_RESIZE_EDGE_NONE;
// Both xdg-shell and wl_shell use the same values.
uint32_t edges = WL_SHELL_SURFACE_RESIZE_NONE;
if (!window) if (!window)
return; return;
@ -251,46 +249,39 @@ static void pointerHandleButton(void* data,
break; break;
case topDecoration: case topDecoration:
if (window->wl.cursorPosY < _GLFW_DECORATION_WIDTH) if (window->wl.cursorPosY < _GLFW_DECORATION_WIDTH)
edges = WL_SHELL_SURFACE_RESIZE_TOP; edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP;
else else
{ {
if (window->wl.xdg.toplevel)
xdg_toplevel_move(window->wl.xdg.toplevel, _glfw.wl.seat, serial); xdg_toplevel_move(window->wl.xdg.toplevel, _glfw.wl.seat, serial);
else
wl_shell_surface_move(window->wl.shellSurface, _glfw.wl.seat, serial);
} }
break; break;
case leftDecoration: case leftDecoration:
if (window->wl.cursorPosY < _GLFW_DECORATION_WIDTH) if (window->wl.cursorPosY < _GLFW_DECORATION_WIDTH)
edges = WL_SHELL_SURFACE_RESIZE_TOP_LEFT; edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT;
else else
edges = WL_SHELL_SURFACE_RESIZE_LEFT; edges = XDG_TOPLEVEL_RESIZE_EDGE_LEFT;
break; break;
case rightDecoration: case rightDecoration:
if (window->wl.cursorPosY < _GLFW_DECORATION_WIDTH) if (window->wl.cursorPosY < _GLFW_DECORATION_WIDTH)
edges = WL_SHELL_SURFACE_RESIZE_TOP_RIGHT; edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT;
else else
edges = WL_SHELL_SURFACE_RESIZE_RIGHT; edges = XDG_TOPLEVEL_RESIZE_EDGE_RIGHT;
break; break;
case bottomDecoration: case bottomDecoration:
if (window->wl.cursorPosX < _GLFW_DECORATION_WIDTH) if (window->wl.cursorPosX < _GLFW_DECORATION_WIDTH)
edges = WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT; edges = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT;
else if (window->wl.cursorPosX > window->wl.width + _GLFW_DECORATION_WIDTH) else if (window->wl.cursorPosX > window->wl.width + _GLFW_DECORATION_WIDTH)
edges = WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT; edges = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT;
else else
edges = WL_SHELL_SURFACE_RESIZE_BOTTOM; edges = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM;
break; break;
default: default:
assert(0); assert(0);
} }
if (edges != WL_SHELL_SURFACE_RESIZE_NONE) if (edges != XDG_TOPLEVEL_RESIZE_EDGE_NONE)
{ {
if (window->wl.xdg.toplevel)
xdg_toplevel_resize(window->wl.xdg.toplevel, _glfw.wl.seat, xdg_toplevel_resize(window->wl.xdg.toplevel, _glfw.wl.seat,
serial, edges); serial, edges);
else
wl_shell_surface_resize(window->wl.shellSurface, _glfw.wl.seat,
serial, edges);
} }
} }
else if (button == BTN_RIGHT) else if (button == BTN_RIGHT)
@ -805,11 +796,6 @@ static void registryHandleGlobal(void* data,
_glfw.wl.shm = _glfw.wl.shm =
wl_registry_bind(registry, name, &wl_shm_interface, 1); wl_registry_bind(registry, name, &wl_shm_interface, 1);
} }
else if (strcmp(interface, "wl_shell") == 0)
{
_glfw.wl.shell =
wl_registry_bind(registry, name, &wl_shell_interface, 1);
}
else if (strcmp(interface, "wl_output") == 0) else if (strcmp(interface, "wl_output") == 0)
{ {
_glfwAddOutputWayland(name, version); _glfwAddOutputWayland(name, version);
@ -1164,6 +1150,13 @@ int _glfwPlatformInit(void)
if (_glfw.wl.seatVersion >= 4) if (_glfw.wl.seatVersion >= 4)
_glfw.wl.timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC); _glfw.wl.timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
if (!_glfw.wl.wmBase)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: Failed to find xdg-shell in your compositor");
return GLFW_FALSE;
}
if (_glfw.wl.pointer && _glfw.wl.shm) if (_glfw.wl.pointer && _glfw.wl.shm)
{ {
cursorTheme = getenv("XCURSOR_THEME"); cursorTheme = getenv("XCURSOR_THEME");
@ -1257,8 +1250,6 @@ void _glfwPlatformTerminate(void)
wl_compositor_destroy(_glfw.wl.compositor); wl_compositor_destroy(_glfw.wl.compositor);
if (_glfw.wl.shm) if (_glfw.wl.shm)
wl_shm_destroy(_glfw.wl.shm); wl_shm_destroy(_glfw.wl.shm);
if (_glfw.wl.shell)
wl_shell_destroy(_glfw.wl.shell);
if (_glfw.wl.viewporter) if (_glfw.wl.viewporter)
wp_viewporter_destroy(_glfw.wl.viewporter); wp_viewporter_destroy(_glfw.wl.viewporter);
if (_glfw.wl.decorationManager) if (_glfw.wl.decorationManager)

View File

@ -180,7 +180,6 @@ typedef struct _GLFWwindowWayland
GLFWbool transparent; GLFWbool transparent;
struct wl_surface* surface; struct wl_surface* surface;
struct wl_egl_window* native; struct wl_egl_window* native;
struct wl_shell_surface* shellSurface;
struct wl_callback* callback; struct wl_callback* callback;
struct { struct {
@ -227,7 +226,6 @@ typedef struct _GLFWlibraryWayland
struct wl_registry* registry; struct wl_registry* registry;
struct wl_compositor* compositor; struct wl_compositor* compositor;
struct wl_subcompositor* subcompositor; struct wl_subcompositor* subcompositor;
struct wl_shell* shell;
struct wl_shm* shm; struct wl_shm* shm;
struct wl_seat* seat; struct wl_seat* seat;
struct wl_pointer* pointer; struct wl_pointer* pointer;

View File

@ -39,72 +39,6 @@
#include <poll.h> #include <poll.h>
static void shellSurfaceHandlePing(void* data,
struct wl_shell_surface* shellSurface,
uint32_t serial)
{
wl_shell_surface_pong(shellSurface, serial);
}
static void shellSurfaceHandleConfigure(void* data,
struct wl_shell_surface* shellSurface,
uint32_t edges,
int32_t width,
int32_t height)
{
_GLFWwindow* window = data;
float aspectRatio;
float targetRatio;
if (!window->monitor)
{
if (_glfw.wl.viewporter && window->decorated)
{
width -= _GLFW_DECORATION_HORIZONTAL;
height -= _GLFW_DECORATION_VERTICAL;
}
if (width < 1)
width = 1;
if (height < 1)
height = 1;
if (window->numer != GLFW_DONT_CARE && window->denom != GLFW_DONT_CARE)
{
aspectRatio = (float)width / (float)height;
targetRatio = (float)window->numer / (float)window->denom;
if (aspectRatio < targetRatio)
height = width / targetRatio;
else if (aspectRatio > targetRatio)
width = height * targetRatio;
}
if (window->minwidth != GLFW_DONT_CARE && width < window->minwidth)
width = window->minwidth;
else if (window->maxwidth != GLFW_DONT_CARE && width > window->maxwidth)
width = window->maxwidth;
if (window->minheight != GLFW_DONT_CARE && height < window->minheight)
height = window->minheight;
else if (window->maxheight != GLFW_DONT_CARE && height > window->maxheight)
height = window->maxheight;
}
_glfwInputWindowSize(window, width, height);
_glfwPlatformSetWindowSize(window, width, height);
_glfwInputWindowDamage(window);
}
static void shellSurfaceHandlePopupDone(void* data,
struct wl_shell_surface* shellSurface)
{
}
static const struct wl_shell_surface_listener shellSurfaceListener = {
shellSurfaceHandlePing,
shellSurfaceHandleConfigure,
shellSurfaceHandlePopupDone
};
static int createTmpfileCloexec(char* tmpname) static int createTmpfileCloexec(char* tmpname)
{ {
int fd; int fd;
@ -529,66 +463,11 @@ static void setFullscreen(_GLFWwindow* window, _GLFWmonitor* monitor,
window->wl.xdg.toplevel, window->wl.xdg.toplevel,
monitor->wl.output); monitor->wl.output);
} }
else if (window->wl.shellSurface)
{
wl_shell_surface_set_fullscreen(
window->wl.shellSurface,
WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT,
refreshRate * 1000, // Convert Hz to mHz.
monitor->wl.output);
}
setIdleInhibitor(window, GLFW_TRUE); setIdleInhibitor(window, GLFW_TRUE);
if (!window->wl.decorations.serverSide) if (!window->wl.decorations.serverSide)
destroyDecorations(window); destroyDecorations(window);
} }
static GLFWbool createShellSurface(_GLFWwindow* window)
{
if (!_glfw.wl.shell)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: wl_shell protocol not available");
return GLFW_FALSE;
}
window->wl.shellSurface = wl_shell_get_shell_surface(_glfw.wl.shell,
window->wl.surface);
if (!window->wl.shellSurface)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: Shell surface creation failed");
return GLFW_FALSE;
}
wl_shell_surface_add_listener(window->wl.shellSurface,
&shellSurfaceListener,
window);
if (window->wl.title)
wl_shell_surface_set_title(window->wl.shellSurface, window->wl.title);
if (window->monitor)
{
setFullscreen(window, window->monitor, 0);
}
else if (window->wl.maximized)
{
wl_shell_surface_set_maximized(window->wl.shellSurface, NULL);
setIdleInhibitor(window, GLFW_FALSE);
createDecorations(window);
}
else
{
wl_shell_surface_set_toplevel(window->wl.shellSurface);
setIdleInhibitor(window, GLFW_FALSE);
createDecorations(window);
}
wl_surface_commit(window->wl.surface);
return GLFW_TRUE;
}
static void xdgToplevelHandleConfigure(void* data, static void xdgToplevelHandleConfigure(void* data,
struct xdg_toplevel* toplevel, struct xdg_toplevel* toplevel,
int32_t width, int32_t width,
@ -948,17 +827,9 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window,
window->wl.title = _glfw_strdup(wndconfig->title); window->wl.title = _glfw_strdup(wndconfig->title);
if (wndconfig->visible) if (wndconfig->visible)
{
if (_glfw.wl.wmBase)
{ {
if (!createXdgSurface(window)) if (!createXdgSurface(window))
return GLFW_FALSE; return GLFW_FALSE;
}
else
{
if (!createShellSurface(window))
return GLFW_FALSE;
}
window->wl.visible = GLFW_TRUE; window->wl.visible = GLFW_TRUE;
} }
@ -966,7 +837,6 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window,
{ {
window->wl.xdg.surface = NULL; window->wl.xdg.surface = NULL;
window->wl.xdg.toplevel = NULL; window->wl.xdg.toplevel = NULL;
window->wl.shellSurface = NULL;
window->wl.visible = GLFW_FALSE; window->wl.visible = GLFW_FALSE;
} }
@ -1008,9 +878,6 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window)
if (window->wl.native) if (window->wl.native)
wl_egl_window_destroy(window->wl.native); wl_egl_window_destroy(window->wl.native);
if (window->wl.shellSurface)
wl_shell_surface_destroy(window->wl.shellSurface);
if (window->wl.xdg.toplevel) if (window->wl.xdg.toplevel)
xdg_toplevel_destroy(window->wl.xdg.toplevel); xdg_toplevel_destroy(window->wl.xdg.toplevel);
@ -1031,8 +898,6 @@ void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title)
window->wl.title = _glfw_strdup(title); window->wl.title = _glfw_strdup(title);
if (window->wl.xdg.toplevel) if (window->wl.xdg.toplevel)
xdg_toplevel_set_title(window->wl.xdg.toplevel, title); xdg_toplevel_set_title(window->wl.xdg.toplevel, title);
else if (window->wl.shellSurface)
wl_shell_surface_set_title(window->wl.shellSurface, title);
} }
void _glfwPlatformSetWindowIcon(_GLFWwindow* window, void _glfwPlatformSetWindowIcon(_GLFWwindow* window,
@ -1078,8 +943,6 @@ void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window,
int minwidth, int minheight, int minwidth, int minheight,
int maxwidth, int maxheight) int maxwidth, int maxheight)
{ {
if (_glfw.wl.wmBase)
{
if (window->wl.xdg.toplevel) if (window->wl.xdg.toplevel)
{ {
if (minwidth == GLFW_DONT_CARE || minheight == GLFW_DONT_CARE) if (minwidth == GLFW_DONT_CARE || minheight == GLFW_DONT_CARE)
@ -1090,19 +953,13 @@ void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window,
xdg_toplevel_set_max_size(window->wl.xdg.toplevel, maxwidth, maxheight); xdg_toplevel_set_max_size(window->wl.xdg.toplevel, maxwidth, maxheight);
wl_surface_commit(window->wl.surface); wl_surface_commit(window->wl.surface);
} }
}
else
{
// TODO: find out how to trigger a resize.
// The actual limits are checked in the wl_shell_surface::configure handler.
}
} }
void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window,
int numer, int denom) int numer, int denom)
{ {
// TODO: find out how to trigger a resize. // TODO: find out how to trigger a resize.
// The actual limits are checked in the wl_shell_surface::configure handler. // The actual limits are checked in the xdg_toplevel::configure handler.
} }
void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, void _glfwPlatformGetFramebufferSize(_GLFWwindow* window,
@ -1141,16 +998,8 @@ void _glfwPlatformGetWindowContentScale(_GLFWwindow* window,
void _glfwPlatformIconifyWindow(_GLFWwindow* window) void _glfwPlatformIconifyWindow(_GLFWwindow* window)
{ {
if (_glfw.wl.wmBase)
{
if (window->wl.xdg.toplevel) if (window->wl.xdg.toplevel)
xdg_toplevel_set_minimized(window->wl.xdg.toplevel); xdg_toplevel_set_minimized(window->wl.xdg.toplevel);
}
else
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: Iconify window not supported on wl_shell");
}
} }
void _glfwPlatformRestoreWindow(_GLFWwindow* window) void _glfwPlatformRestoreWindow(_GLFWwindow* window)
@ -1162,12 +1011,7 @@ void _glfwPlatformRestoreWindow(_GLFWwindow* window)
if (window->wl.maximized) if (window->wl.maximized)
xdg_toplevel_unset_maximized(window->wl.xdg.toplevel); xdg_toplevel_unset_maximized(window->wl.xdg.toplevel);
// There is no way to unset minimized, or even to know if we are // There is no way to unset minimized, or even to know if we are
// minimized, so there is nothing to do here. // minimized, so there is nothing to do in this case.
}
else if (window->wl.shellSurface)
{
if (window->monitor || window->wl.maximized)
wl_shell_surface_set_toplevel(window->wl.shellSurface);
} }
_glfwInputWindowMonitor(window, NULL); _glfwInputWindowMonitor(window, NULL);
window->wl.maximized = GLFW_FALSE; window->wl.maximized = GLFW_FALSE;
@ -1179,11 +1023,6 @@ void _glfwPlatformMaximizeWindow(_GLFWwindow* window)
{ {
xdg_toplevel_set_maximized(window->wl.xdg.toplevel); xdg_toplevel_set_maximized(window->wl.xdg.toplevel);
} }
else if (window->wl.shellSurface)
{
// Let the compositor select the best output.
wl_shell_surface_set_maximized(window->wl.shellSurface, NULL);
}
window->wl.maximized = GLFW_TRUE; window->wl.maximized = GLFW_TRUE;
} }
@ -1191,10 +1030,7 @@ void _glfwPlatformShowWindow(_GLFWwindow* window)
{ {
if (!window->wl.visible) if (!window->wl.visible)
{ {
if (_glfw.wl.wmBase)
createXdgSurface(window); createXdgSurface(window);
else if (!window->wl.shellSurface)
createShellSurface(window);
window->wl.visible = GLFW_TRUE; window->wl.visible = GLFW_TRUE;
} }
} }
@ -1208,11 +1044,6 @@ void _glfwPlatformHideWindow(_GLFWwindow* window)
window->wl.xdg.toplevel = NULL; window->wl.xdg.toplevel = NULL;
window->wl.xdg.surface = NULL; window->wl.xdg.surface = NULL;
} }
else if (window->wl.shellSurface)
{
wl_shell_surface_destroy(window->wl.shellSurface);
window->wl.shellSurface = NULL;
}
window->wl.visible = GLFW_FALSE; window->wl.visible = GLFW_FALSE;
} }
@ -1243,8 +1074,6 @@ void _glfwPlatformSetWindowMonitor(_GLFWwindow* window,
{ {
if (window->wl.xdg.toplevel) if (window->wl.xdg.toplevel)
xdg_toplevel_unset_fullscreen(window->wl.xdg.toplevel); xdg_toplevel_unset_fullscreen(window->wl.xdg.toplevel);
else if (window->wl.shellSurface)
wl_shell_surface_set_toplevel(window->wl.shellSurface);
setIdleInhibitor(window, GLFW_FALSE); setIdleInhibitor(window, GLFW_FALSE);
if (!_glfw.wl.decorationManager) if (!_glfw.wl.decorationManager)
createDecorations(window); createDecorations(window);
@ -1259,8 +1088,8 @@ int _glfwPlatformWindowFocused(_GLFWwindow* window)
int _glfwPlatformWindowIconified(_GLFWwindow* window) int _glfwPlatformWindowIconified(_GLFWwindow* window)
{ {
// wl_shell doesn't have any iconified concept, and xdg-shell doesnt give // xdg-shell doesnt give any way to request whether a surface is
// any way to request whether a surface is iconified. // iconified.
return GLFW_FALSE; return GLFW_FALSE;
} }