Wayland: Put fallback decorations behind a boolean

This commit is contained in:
Camilla Löwy 2024-02-07 22:56:18 +01:00
parent 6ac0835ad2
commit 4baeadbd66
2 changed files with 159 additions and 142 deletions

View File

@ -410,6 +410,7 @@ typedef struct _GLFWwindowWayland
struct xdg_activation_token_v1* activationToken; struct xdg_activation_token_v1* activationToken;
struct { struct {
GLFWbool decorations;
struct wl_buffer* buffer; struct wl_buffer* buffer;
_GLFWdecorationWayland top, left, right, bottom; _GLFWdecorationWayland top, left, right, bottom;
_GLFWdecorationSideWayland focus; _GLFWdecorationSideWayland focus;

View File

@ -247,6 +247,8 @@ static void createFallbackDecorations(_GLFWwindow* window)
window->wl.fallback.buffer, window->wl.fallback.buffer,
-GLFW_BORDER_SIZE, window->wl.height, -GLFW_BORDER_SIZE, window->wl.height,
window->wl.width + GLFW_BORDER_SIZE * 2, GLFW_BORDER_SIZE); window->wl.width + GLFW_BORDER_SIZE * 2, GLFW_BORDER_SIZE);
window->wl.fallback.decorations = GLFW_TRUE;
} }
static void destroyFallbackDecoration(_GLFWdecorationWayland* decoration) static void destroyFallbackDecoration(_GLFWdecorationWayland* decoration)
@ -264,6 +266,8 @@ static void destroyFallbackDecoration(_GLFWdecorationWayland* decoration)
static void destroyFallbackDecorations(_GLFWwindow* window) static void destroyFallbackDecorations(_GLFWwindow* window)
{ {
window->wl.fallback.decorations = GLFW_FALSE;
destroyFallbackDecoration(&window->wl.fallback.top); destroyFallbackDecoration(&window->wl.fallback.top);
destroyFallbackDecoration(&window->wl.fallback.left); destroyFallbackDecoration(&window->wl.fallback.left);
destroyFallbackDecoration(&window->wl.fallback.right); destroyFallbackDecoration(&window->wl.fallback.right);
@ -325,28 +329,32 @@ static void resizeWindow(_GLFWwindow* window)
{ {
resizeFramebuffer(window); resizeFramebuffer(window);
if (!window->wl.fallback.top.surface) if (window->wl.fallback.decorations)
return; {
wp_viewport_set_destination(window->wl.fallback.top.viewport,
window->wl.width,
GLFW_CAPTION_HEIGHT);
wl_surface_commit(window->wl.fallback.top.surface);
wp_viewport_set_destination(window->wl.fallback.top.viewport, wp_viewport_set_destination(window->wl.fallback.left.viewport,
window->wl.width, GLFW_CAPTION_HEIGHT); GLFW_BORDER_SIZE,
wl_surface_commit(window->wl.fallback.top.surface); window->wl.height + GLFW_CAPTION_HEIGHT);
wl_surface_commit(window->wl.fallback.left.surface);
wp_viewport_set_destination(window->wl.fallback.left.viewport, wl_subsurface_set_position(window->wl.fallback.right.subsurface,
GLFW_BORDER_SIZE, window->wl.height + GLFW_CAPTION_HEIGHT); window->wl.width, -GLFW_CAPTION_HEIGHT);
wl_surface_commit(window->wl.fallback.left.surface); wp_viewport_set_destination(window->wl.fallback.right.viewport,
GLFW_BORDER_SIZE,
window->wl.height + GLFW_CAPTION_HEIGHT);
wl_surface_commit(window->wl.fallback.right.surface);
wl_subsurface_set_position(window->wl.fallback.right.subsurface, wl_subsurface_set_position(window->wl.fallback.bottom.subsurface,
window->wl.width, -GLFW_CAPTION_HEIGHT); -GLFW_BORDER_SIZE, window->wl.height);
wp_viewport_set_destination(window->wl.fallback.right.viewport, wp_viewport_set_destination(window->wl.fallback.bottom.viewport,
GLFW_BORDER_SIZE, window->wl.height + GLFW_CAPTION_HEIGHT); window->wl.width + GLFW_BORDER_SIZE * 2,
wl_surface_commit(window->wl.fallback.right.surface); GLFW_BORDER_SIZE);
wl_surface_commit(window->wl.fallback.bottom.surface);
wl_subsurface_set_position(window->wl.fallback.bottom.subsurface, }
-GLFW_BORDER_SIZE, window->wl.height);
wp_viewport_set_destination(window->wl.fallback.bottom.viewport,
window->wl.width + GLFW_BORDER_SIZE * 2, GLFW_BORDER_SIZE);
wl_surface_commit(window->wl.fallback.bottom.surface);
} }
void _glfwUpdateContentScaleWayland(_GLFWwindow* window) void _glfwUpdateContentScaleWayland(_GLFWwindow* window)
@ -466,7 +474,7 @@ static void acquireMonitor(_GLFWwindow* window)
setIdleInhibitor(window, GLFW_TRUE); setIdleInhibitor(window, GLFW_TRUE);
if (window->wl.fallback.top.surface) if (window->wl.fallback.decorations)
destroyFallbackDecorations(window); destroyFallbackDecorations(window);
} }
@ -522,7 +530,7 @@ static void xdgToplevelHandleConfigure(void* userData,
if (width && height) if (width && height)
{ {
if (window->wl.fallback.top.surface) if (window->wl.fallback.decorations)
{ {
window->wl.pending.width = _glfw_max(0, width - GLFW_BORDER_SIZE * 2); window->wl.pending.width = _glfw_max(0, width - GLFW_BORDER_SIZE * 2);
window->wl.pending.height = window->wl.pending.height =
@ -882,7 +890,7 @@ static GLFWbool createXdgShellObjects(_GLFWwindow* window)
int minwidth = window->minwidth; int minwidth = window->minwidth;
int minheight = window->minheight; int minheight = window->minheight;
if (window->wl.fallback.top.surface) if (window->wl.fallback.decorations)
{ {
minwidth += GLFW_BORDER_SIZE * 2; minwidth += GLFW_BORDER_SIZE * 2;
minheight += GLFW_CAPTION_HEIGHT + GLFW_BORDER_SIZE; minheight += GLFW_CAPTION_HEIGHT + GLFW_BORDER_SIZE;
@ -896,7 +904,7 @@ static GLFWbool createXdgShellObjects(_GLFWwindow* window)
int maxwidth = window->maxwidth; int maxwidth = window->maxwidth;
int maxheight = window->maxheight; int maxheight = window->maxheight;
if (window->wl.fallback.top.surface) if (window->wl.fallback.decorations)
{ {
maxwidth += GLFW_BORDER_SIZE * 2; maxwidth += GLFW_BORDER_SIZE * 2;
maxheight += GLFW_CAPTION_HEIGHT + GLFW_BORDER_SIZE; maxheight += GLFW_CAPTION_HEIGHT + GLFW_BORDER_SIZE;
@ -1276,23 +1284,25 @@ static void pointerHandleEnter(void* userData,
_GLFWwindow* window = wl_surface_get_user_data(surface); _GLFWwindow* window = wl_surface_get_user_data(surface);
if (surface == window->wl.surface) if (window->wl.fallback.decorations)
window->wl.hovered = GLFW_TRUE; {
else if (surface == window->wl.fallback.top.surface) if (surface == window->wl.fallback.top.surface)
window->wl.fallback.focus = GLFW_TOP_DECORATION; window->wl.fallback.focus = GLFW_TOP_DECORATION;
else if (surface == window->wl.fallback.left.surface) else if (surface == window->wl.fallback.left.surface)
window->wl.fallback.focus = GLFW_LEFT_DECORATION; window->wl.fallback.focus = GLFW_LEFT_DECORATION;
else if (surface == window->wl.fallback.right.surface) else if (surface == window->wl.fallback.right.surface)
window->wl.fallback.focus = GLFW_RIGHT_DECORATION; window->wl.fallback.focus = GLFW_RIGHT_DECORATION;
else if (surface == window->wl.fallback.bottom.surface) else if (surface == window->wl.fallback.bottom.surface)
window->wl.fallback.focus = GLFW_BOTTOM_DECORATION; window->wl.fallback.focus = GLFW_BOTTOM_DECORATION;
}
_glfw.wl.serial = serial; _glfw.wl.serial = serial;
_glfw.wl.pointerEnterSerial = serial; _glfw.wl.pointerEnterSerial = serial;
_glfw.wl.pointerFocus = window; _glfw.wl.pointerFocus = window;
if (window->wl.hovered) if (surface == window->wl.surface)
{ {
window->wl.hovered = GLFW_TRUE;
_glfwSetCursorWayland(window, window->wl.currentCursor); _glfwSetCursorWayland(window, window->wl.currentCursor);
_glfwInputCursorEnter(window, GLFW_TRUE); _glfwInputCursorEnter(window, GLFW_TRUE);
} }
@ -1349,77 +1359,80 @@ static void pointerHandleMotion(void* userData,
return; return;
} }
const char* cursorName = NULL; if (window->wl.fallback.decorations)
switch (window->wl.fallback.focus)
{ {
case GLFW_TOP_DECORATION: const char* cursorName = NULL;
if (ypos < GLFW_BORDER_SIZE)
cursorName = "n-resize";
else
cursorName = "left_ptr";
break;
case GLFW_LEFT_DECORATION:
if (ypos < GLFW_BORDER_SIZE)
cursorName = "nw-resize";
else
cursorName = "w-resize";
break;
case GLFW_RIGHT_DECORATION:
if (ypos < GLFW_BORDER_SIZE)
cursorName = "ne-resize";
else
cursorName = "e-resize";
break;
case GLFW_BOTTOM_DECORATION:
if (xpos < GLFW_BORDER_SIZE)
cursorName = "sw-resize";
else if (xpos > window->wl.width + GLFW_BORDER_SIZE)
cursorName = "se-resize";
else
cursorName = "s-resize";
break;
default:
assert(0);
}
if (_glfw.wl.cursorPreviousName != cursorName) switch (window->wl.fallback.focus)
{
struct wl_surface* surface = _glfw.wl.cursorSurface;
struct wl_cursor_theme* theme = _glfw.wl.cursorTheme;
int scale = 1;
if (window->wl.contentScale > 1 && _glfw.wl.cursorThemeHiDPI)
{ {
// We only support up to scale=2 for now, since libwayland-cursor case GLFW_TOP_DECORATION:
// requires us to load a different theme for each size. if (ypos < GLFW_BORDER_SIZE)
scale = 2; cursorName = "n-resize";
theme = _glfw.wl.cursorThemeHiDPI; else
cursorName = "left_ptr";
break;
case GLFW_LEFT_DECORATION:
if (ypos < GLFW_BORDER_SIZE)
cursorName = "nw-resize";
else
cursorName = "w-resize";
break;
case GLFW_RIGHT_DECORATION:
if (ypos < GLFW_BORDER_SIZE)
cursorName = "ne-resize";
else
cursorName = "e-resize";
break;
case GLFW_BOTTOM_DECORATION:
if (xpos < GLFW_BORDER_SIZE)
cursorName = "sw-resize";
else if (xpos > window->wl.width + GLFW_BORDER_SIZE)
cursorName = "se-resize";
else
cursorName = "s-resize";
break;
default:
assert(0);
} }
struct wl_cursor* cursor = wl_cursor_theme_get_cursor(theme, cursorName); if (_glfw.wl.cursorPreviousName != cursorName)
if (!cursor) {
return; struct wl_surface* surface = _glfw.wl.cursorSurface;
struct wl_cursor_theme* theme = _glfw.wl.cursorTheme;
int scale = 1;
// TODO: handle animated cursors too. if (window->wl.contentScale > 1 && _glfw.wl.cursorThemeHiDPI)
struct wl_cursor_image* image = cursor->images[0]; {
if (!image) // We only support up to scale=2 for now, since libwayland-cursor
return; // requires us to load a different theme for each size.
scale = 2;
theme = _glfw.wl.cursorThemeHiDPI;
}
struct wl_buffer* buffer = wl_cursor_image_get_buffer(image); struct wl_cursor* cursor = wl_cursor_theme_get_cursor(theme, cursorName);
if (!buffer) if (!cursor)
return; return;
wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerEnterSerial, // TODO: handle animated cursors too.
surface, struct wl_cursor_image* image = cursor->images[0];
image->hotspot_x / scale, if (!image)
image->hotspot_y / scale); return;
wl_surface_set_buffer_scale(surface, scale);
wl_surface_attach(surface, buffer, 0, 0);
wl_surface_damage(surface, 0, 0, image->width, image->height);
wl_surface_commit(surface);
_glfw.wl.cursorPreviousName = cursorName; struct wl_buffer* buffer = wl_cursor_image_get_buffer(image);
if (!buffer)
return;
wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerEnterSerial,
surface,
image->hotspot_x / scale,
image->hotspot_y / scale);
wl_surface_set_buffer_scale(surface, scale);
wl_surface_attach(surface, buffer, 0, 0);
wl_surface_damage(surface, 0, 0, image->width, image->height);
wl_surface_commit(surface);
_glfw.wl.cursorPreviousName = cursorName;
}
} }
} }
@ -1445,53 +1458,56 @@ static void pointerHandleButton(void* userData,
return; return;
} }
if (button == BTN_LEFT) if (window->wl.fallback.decorations)
{ {
uint32_t edges = XDG_TOPLEVEL_RESIZE_EDGE_NONE; if (button == BTN_LEFT)
{
uint32_t edges = XDG_TOPLEVEL_RESIZE_EDGE_NONE;
switch (window->wl.fallback.focus) switch (window->wl.fallback.focus)
{ {
case GLFW_TOP_DECORATION: case GLFW_TOP_DECORATION:
if (window->wl.cursorPosY < GLFW_BORDER_SIZE) if (window->wl.cursorPosY < GLFW_BORDER_SIZE)
edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP; edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP;
else else
xdg_toplevel_move(window->wl.xdg.toplevel, _glfw.wl.seat, serial); xdg_toplevel_move(window->wl.xdg.toplevel, _glfw.wl.seat, serial);
break; break;
case GLFW_LEFT_DECORATION: case GLFW_LEFT_DECORATION:
if (window->wl.cursorPosY < GLFW_BORDER_SIZE) if (window->wl.cursorPosY < GLFW_BORDER_SIZE)
edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT; edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT;
else else
edges = XDG_TOPLEVEL_RESIZE_EDGE_LEFT; edges = XDG_TOPLEVEL_RESIZE_EDGE_LEFT;
break; break;
case GLFW_RIGHT_DECORATION: case GLFW_RIGHT_DECORATION:
if (window->wl.cursorPosY < GLFW_BORDER_SIZE) if (window->wl.cursorPosY < GLFW_BORDER_SIZE)
edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT; edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT;
else else
edges = XDG_TOPLEVEL_RESIZE_EDGE_RIGHT; edges = XDG_TOPLEVEL_RESIZE_EDGE_RIGHT;
break; break;
case GLFW_BOTTOM_DECORATION: case GLFW_BOTTOM_DECORATION:
if (window->wl.cursorPosX < GLFW_BORDER_SIZE) if (window->wl.cursorPosX < GLFW_BORDER_SIZE)
edges = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT; edges = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT;
else if (window->wl.cursorPosX > window->wl.width + GLFW_BORDER_SIZE) else if (window->wl.cursorPosX > window->wl.width + GLFW_BORDER_SIZE)
edges = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT; edges = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT;
else else
edges = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM; edges = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM;
break; break;
}
if (edges != XDG_TOPLEVEL_RESIZE_EDGE_NONE)
{
xdg_toplevel_resize(window->wl.xdg.toplevel, _glfw.wl.seat,
serial, edges);
}
} }
if (edges != XDG_TOPLEVEL_RESIZE_EDGE_NONE) else if (button == BTN_RIGHT)
{ {
xdg_toplevel_resize(window->wl.xdg.toplevel, _glfw.wl.seat, if (window->wl.xdg.toplevel)
serial, edges); {
} xdg_toplevel_show_window_menu(window->wl.xdg.toplevel,
} _glfw.wl.seat, serial,
else if (button == BTN_RIGHT) window->wl.cursorPosX,
{ window->wl.cursorPosY);
if (window->wl.xdg.toplevel) }
{
xdg_toplevel_show_window_menu(window->wl.xdg.toplevel,
_glfw.wl.seat, serial,
window->wl.cursorPosX,
window->wl.cursorPosY);
} }
} }
} }
@ -2199,7 +2215,7 @@ void _glfwSetWindowSizeLimitsWayland(_GLFWwindow* window,
minwidth = minheight = 0; minwidth = minheight = 0;
else else
{ {
if (window->wl.fallback.top.surface) if (window->wl.fallback.decorations)
{ {
minwidth += GLFW_BORDER_SIZE * 2; minwidth += GLFW_BORDER_SIZE * 2;
minheight += GLFW_CAPTION_HEIGHT + GLFW_BORDER_SIZE; minheight += GLFW_CAPTION_HEIGHT + GLFW_BORDER_SIZE;
@ -2210,7 +2226,7 @@ void _glfwSetWindowSizeLimitsWayland(_GLFWwindow* window,
maxwidth = maxheight = 0; maxwidth = maxheight = 0;
else else
{ {
if (window->wl.fallback.top.surface) if (window->wl.fallback.decorations)
{ {
maxwidth += GLFW_BORDER_SIZE * 2; maxwidth += GLFW_BORDER_SIZE * 2;
maxheight += GLFW_CAPTION_HEIGHT + GLFW_BORDER_SIZE; maxheight += GLFW_CAPTION_HEIGHT + GLFW_BORDER_SIZE;
@ -2273,7 +2289,7 @@ void _glfwGetWindowFrameSizeWayland(_GLFWwindow* window,
int* left, int* top, int* left, int* top,
int* right, int* bottom) int* right, int* bottom)
{ {
if (window->wl.fallback.top.surface) if (window->wl.fallback.decorations)
{ {
if (top) if (top)
*top = GLFW_CAPTION_HEIGHT; *top = GLFW_CAPTION_HEIGHT;