Use individual surfaces for corner and bar shadows

Simplifies a bunch of code and also gives us the option at a later date
to turn off some shadows selectively when the window is in a tiled
state.
This commit is contained in:
Kovid Goyal
2024-04-07 22:28:41 +05:30
parent 38daac868a
commit bf60321466
4 changed files with 232 additions and 276 deletions

View File

@@ -22,6 +22,7 @@
#define B(x) ((x) & 0xff) #define B(x) ((x) & 0xff)
#define SWAP(x, y) do { __typeof__(x) SWAP = x; x = y; y = SWAP; } while (0) #define SWAP(x, y) do { __typeof__(x) SWAP = x; x = y; y = SWAP; } while (0)
// shadow tile {{{
typedef float kernel_type; typedef float kernel_type;
static void static void
@@ -83,6 +84,27 @@ create_shadow_mask(size_t width, size_t height, size_t margin, size_t kernel_siz
return mask; return mask;
} }
#define st decs.shadow_tile
static size_t
create_shadow_tile(_GLFWwindow *window) {
const size_t margin = (size_t)roundf(decs.metrics.width * decs.for_window_state.fscale);
if (st.data && st.for_decoration_size == margin) return margin;
st.for_decoration_size = margin;
free(st.data);
st.segments = 7;
st.stride = st.segments * margin;
st.corner_size = margin * (st.segments - 1) / 2;
kernel_type* mask = create_shadow_mask(st.stride, st.stride, margin, 2 * margin + 1, (kernel_type)0.7, 32 * margin);
st.data = malloc(sizeof(uint32_t) * st.stride * st.stride);
if (st.data) for (size_t i = 0; i < st.stride * st.stride; i++) st.data[i] = ((uint8_t)(mask[i] * 255)) << 24;
free(mask);
return margin;
}
// }}}
static void static void
swap_buffers(_GLFWWaylandBufferPair *pair) { swap_buffers(_GLFWWaylandBufferPair *pair) {
SWAP(pair->front, pair->back); SWAP(pair->front, pair->back);
@@ -100,10 +122,14 @@ init_buffer_pair(_GLFWWaylandBufferPair *pair, size_t width, size_t height, floa
return 2 * pair->size_in_bytes; return 2 * pair->size_in_bytes;
} }
#define all_shadow_surfaces(Q) Q(shadow_left); Q(shadow_top); Q(shadow_right); Q(shadow_bottom); \
Q(shadow_upper_left); Q(shadow_upper_right); Q(shadow_lower_left); Q(shadow_lower_right);
#define all_surfaces(Q) Q(titlebar); all_shadow_surfaces(Q);
static bool static bool
window_has_buffer(_GLFWwindow *window, struct wl_buffer *q) { window_has_buffer(_GLFWwindow *window, struct wl_buffer *q) {
#define Q(which) if (decs.which.buffer.a == q) { decs.which.buffer.a_needs_to_be_destroyed = false; return true; } if (decs.which.buffer.b == q) { decs.which.buffer.b_needs_to_be_destroyed = false; return true; } #define Q(which) if (decs.which.buffer.a == q) { decs.which.buffer.a_needs_to_be_destroyed = false; return true; } if (decs.which.buffer.b == q) { decs.which.buffer.b_needs_to_be_destroyed = false; return true; }
Q(left); Q(top); Q(right); Q(bottom); all_surfaces(Q);
#undef Q #undef Q
return false; return false;
} }
@@ -133,8 +159,6 @@ alloc_buffer_pair(uintptr_t window_id, _GLFWWaylandBufferPair *pair, struct wl_s
pair->data.front = pair->data.a; pair->data.back = pair->data.b; pair->data.front = pair->data.a; pair->data.back = pair->data.b;
} }
#define st decs.shadow_tile
void void
csd_initialize_metrics(_GLFWwindow *window) { csd_initialize_metrics(_GLFWwindow *window) {
decs.metrics.width = 12; decs.metrics.width = 12;
@@ -144,22 +168,6 @@ csd_initialize_metrics(_GLFWwindow *window) {
decs.metrics.vertical = decs.metrics.width + decs.metrics.top; decs.metrics.vertical = decs.metrics.width + decs.metrics.top;
} }
static size_t
create_shadow_tile(_GLFWwindow *window) {
const size_t margin = decs.bottom.buffer.height;
if (st.data && st.for_decoration_size == margin) return margin;
st.for_decoration_size = margin;
free(st.data);
st.segments = 7;
st.stride = st.segments * margin;
st.corner_size = margin * (st.segments - 1) / 2;
kernel_type* mask = create_shadow_mask(st.stride, st.stride, margin, 2 * margin + 1, (kernel_type)0.7, 32 * margin);
st.data = malloc(sizeof(uint32_t) * st.stride * st.stride);
if (st.data) for (size_t i = 0; i < st.stride * st.stride; i++) st.data[i] = ((uint8_t)(mask[i] * 255)) << 24;
free(mask);
return margin;
}
static void static void
render_title_bar(_GLFWwindow *window, bool to_front_buffer) { render_title_bar(_GLFWwindow *window, bool to_front_buffer) {
@@ -179,45 +187,26 @@ render_title_bar(_GLFWwindow *window, bool to_front_buffer) {
if (luma < 0.5) { fg_color = dark_fg; hover_bg = hover_dark_bg; is_dark = true; } if (luma < 0.5) { fg_color = dark_fg; hover_bg = hover_dark_bg; is_dark = true; }
if (!decs.use_custom_titlebar_color) bg_color = luma < 0.5 ? dark_bg : light_bg; if (!decs.use_custom_titlebar_color) bg_color = luma < 0.5 ? dark_bg : light_bg;
} else if (appearance == GLFW_COLOR_SCHEME_DARK) { bg_color = dark_bg; fg_color = dark_fg; hover_bg = hover_dark_bg; is_dark = true; } } else if (appearance == GLFW_COLOR_SCHEME_DARK) { bg_color = dark_bg; fg_color = dark_fg; hover_bg = hover_dark_bg; is_dark = true; }
uint8_t *output = to_front_buffer ? decs.top.buffer.data.front : decs.top.buffer.data.back; uint8_t *output = to_front_buffer ? decs.titlebar.buffer.data.front : decs.titlebar.buffer.data.back;
// render shadow part
const size_t margin = create_shadow_tile(window);
const size_t edge_segment_size = st.corner_size - margin;
const uint8_t divisor = is_focused ? 1 : 2;
for (size_t y = 0; y < margin; y++) {
// left segment
uint32_t *s = st.data + y * st.stride + margin;
uint32_t *d = (uint32_t*)(output + y * decs.top.buffer.stride);
for (size_t x = 0; x < edge_segment_size; x++) d[x] = (A(s[x]) / divisor) << 24;
// middle segment
s += edge_segment_size;
size_t limit = decs.top.buffer.width > edge_segment_size ? decs.top.buffer.width - edge_segment_size : 0;
for (size_t x = edge_segment_size, sx = 0; x < limit; x++, sx = (sx + 1) % margin) d[x] = (A(s[sx]) / divisor) << 24;
// right segment
s += margin;
for (size_t x = limit; x < decs.top.buffer.width; x++, s++) d[x] = (A(*s) / divisor) << 24;
}
// render text part // render text part
int button_size = (int)roundf(decs.metrics.visible_titlebar_height * decs.for_window_state.fscale); int button_size = (int)roundf(decs.metrics.visible_titlebar_height * decs.for_window_state.fscale);
int num_buttons = 1; int num_buttons = 1;
if (window->wl.wm_capabilities.maximize) num_buttons++; if (window->wl.wm_capabilities.maximize) num_buttons++;
if (window->wl.wm_capabilities.minimize) num_buttons++; if (window->wl.wm_capabilities.minimize) num_buttons++;
output += decs.top.buffer.stride * margin;
if (window->wl.title && window->wl.title[0] && _glfw.callbacks.draw_text) { if (window->wl.title && window->wl.title[0] && _glfw.callbacks.draw_text) {
if (_glfw.callbacks.draw_text((GLFWwindow*)window, window->wl.title, fg_color, bg_color, output, decs.top.buffer.width, decs.top.buffer.height - margin, 0, 0, num_buttons * button_size, false)) goto render_buttons; if (_glfw.callbacks.draw_text((GLFWwindow*)window, window->wl.title, fg_color, bg_color, output, decs.titlebar.buffer.width, decs.titlebar.buffer.height, 0, 0, num_buttons * button_size, false)) goto render_buttons;
} }
// rendering of text failed, blank the buffer // rendering of text failed, blank the buffer
for (uint32_t *px = (uint32_t*)output, *end = (uint32_t*)(output + decs.top.buffer.size_in_bytes); px < end; px++) *px = bg_color; for (uint32_t *px = (uint32_t*)output, *end = (uint32_t*)(output + decs.titlebar.buffer.size_in_bytes); px < end; px++) *px = bg_color;
render_buttons: render_buttons:
decs.maximize.width = 0; decs.minimize.width = 0; decs.close.width = 0; decs.maximize.width = 0; decs.minimize.width = 0; decs.close.width = 0;
if (!button_size) return; if (!button_size) return;
int left = decs.top.buffer.width - num_buttons * button_size; int left = decs.titlebar.buffer.width - num_buttons * button_size;
#define draw(which, text, hover_bg) { \ #define draw(which, text, hover_bg) { \
_glfw.callbacks.draw_text((GLFWwindow*)window, text, fg_color, decs.which.hovered ? hover_bg : bg_color, output, decs.top.buffer.width, \ _glfw.callbacks.draw_text((GLFWwindow*)window, text, fg_color, decs.which.hovered ? hover_bg : bg_color, output, decs.titlebar.buffer.width, \
decs.top.buffer.height - margin, /*x=*/left, /*y=*/0, /*right_margin=*/decs.top.buffer.width - left - button_size, true); \ decs.titlebar.buffer.height, /*x=*/left, /*y=*/0, /*right_margin=*/decs.titlebar.buffer.width - left - button_size, true); \
decs.which.left = left; decs.which.width = button_size; left += button_size; \ decs.which.left = left; decs.which.width = button_size; left += button_size; \
} }
if (window->wl.wm_capabilities.minimize) draw(minimize, "🗕", hover_bg); if (window->wl.wm_capabilities.minimize) draw(minimize, "🗕", hover_bg);
@@ -229,70 +218,88 @@ render_buttons:
static void static void
update_title_bar(_GLFWwindow *window) { update_title_bar(_GLFWwindow *window) {
render_title_bar(window, false); render_title_bar(window, false);
swap_buffers(&decs.top.buffer); swap_buffers(&decs.titlebar.buffer);
} }
static void static void
render_edges(_GLFWwindow *window) { render_horizontal_shadow(_GLFWwindow *window, ssize_t scaled_shadow_size, ssize_t src_y_offset, ssize_t y, _GLFWWaylandBufferPair *buf) {
const size_t margin = create_shadow_tile(window); // left region
if (!st.data) return; // out of memory ssize_t src_y = src_y_offset + y;
const ssize_t src_leftover_corner = st.corner_size - scaled_shadow_size;
uint32_t *src = st.data + st.stride * src_y + scaled_shadow_size;
uint32_t *d_start = (uint32_t*)(buf->data.front + y * buf->stride);
uint32_t *d_end = (uint32_t*)(buf->data.front + (y+1) * buf->stride);
uint32_t *left_region_end = d_start + MIN(d_end - d_start, src_leftover_corner);
memcpy(d_start, src, sizeof(uint32_t) * (left_region_end - d_start));
// right region
uint32_t *right_region_start = MAX(d_start, d_end - src_leftover_corner);
src = st.data + st.stride * (src_y+1) - st.corner_size;
memcpy(right_region_start, src, sizeof(uint32_t) * MIN(src_leftover_corner, d_end - right_region_start));
src = st.data + st.stride * src_y + st.corner_size;
// middle region
for (uint32_t *d = left_region_end; d < right_region_start; d += scaled_shadow_size)
memcpy(d, src, sizeof(uint32_t) * MIN(right_region_start - d, scaled_shadow_size));
}
// bottom edge static void
uint32_t *src = st.data + (st.segments - 1) * margin * st.stride; copy_vertical_region(
for (size_t y = 0; y < margin; y++) { _GLFWwindow *window, ssize_t src_y_start, ssize_t src_y_limit,
uint32_t *d = (uint32_t*)(decs.bottom.buffer.data.front + y * decs.bottom.buffer.stride); ssize_t y_start, ssize_t y_limit, ssize_t src_x_offset, _GLFWWaylandBufferPair *buf
uint32_t *s = src + st.stride * y; ) {
// left corner for (ssize_t dy = y_start, sy = src_y_start; dy < y_limit && sy < src_y_limit; dy++, sy++)
for (size_t x = 0; x < st.corner_size && x < decs.bottom.buffer.width; x++) d[x] = s[x]; memcpy(buf->data.front + dy * buf->stride, st.data + sy * st.stride + src_x_offset, sizeof(uint32_t) * buf->width);
// middle }
size_t pos = st.corner_size, limit = decs.bottom.buffer.width > st.corner_size ? decs.bottom.buffer.width - st.corner_size : 0;
s += st.corner_size;
while (pos < limit) {
uint32_t *p = d + pos;
for (size_t x = 0; x < margin && pos + x < limit; x++) p[x] = s[x];
pos += margin;
}
// right corner
s += margin;
for (size_t x = 0; x < st.corner_size && limit + x < decs.bottom.buffer.width; x++) d[limit + x] = s[x];
}
// upper corners static void
for (size_t y = 0; y < st.corner_size && y < decs.left.buffer.height; y++) { render_shadows(_GLFWwindow *window) {
uint32_t *left_src = st.data + st.stride * y; const ssize_t scaled_shadow_size = create_shadow_tile(window);
uint32_t *left_dest = (uint32_t*)(decs.left.buffer.data.front + y * decs.left.buffer.stride); if (!st.data || !scaled_shadow_size) return; // out of memory
memcpy(left_dest, left_src, margin * sizeof(uint32_t)); // upper and lower shadows
uint32_t *right_src = left_src + 2 * st.corner_size; for (ssize_t y = 0; y < scaled_shadow_size; y++) {
uint32_t *right_dest = (uint32_t*)(decs.right.buffer.data.front + y * decs.right.buffer.stride); _GLFWWaylandBufferPair *buf = &decs.shadow_upper_left.buffer;
memcpy(right_dest, right_src, margin * sizeof(uint32_t)); uint32_t *src = st.data + st.stride * y;
} uint32_t *d = (uint32_t*)(buf->data.front + y * buf->stride);
memcpy(d, src, sizeof(uint32_t) * scaled_shadow_size);
// lower corners buf = &decs.shadow_upper_right.buffer;
size_t src_height = st.corner_size - margin; src += st.stride - scaled_shadow_size;
size_t dest_top = decs.left.buffer.height > src_height ? decs.left.buffer.height - src_height : 0; d = (uint32_t*)(buf->data.front + y * buf->stride);
size_t src_top = st.corner_size + margin; memcpy(d, src, sizeof(uint32_t) * scaled_shadow_size);
for (size_t src_y = src_top, dest_y = dest_top; src_y < src_top + src_height && dest_y < decs.left.buffer.height; src_y++, dest_y++) {
uint32_t *s = st.data + st.stride * src_y;
uint32_t *d = (uint32_t*)(decs.left.buffer.data.front + dest_y * decs.left.buffer.stride);
memcpy(d, s, margin * sizeof(uint32_t));
s += 2 * st.corner_size;
d = (uint32_t*)(decs.right.buffer.data.front + dest_y * decs.left.buffer.stride);
memcpy(d, s, margin * sizeof(uint32_t));
}
// sides const size_t tile_bottom_start = st.stride - scaled_shadow_size;
size_t limit = decs.left.buffer.height > src_height ? decs.left.buffer.height - src_height : 0; buf = &decs.shadow_lower_left.buffer;
for (size_t dest_y = st.corner_size, src_y = 0; dest_y < limit; dest_y++, src_y = (src_y + 1) % margin) { src = st.data + (tile_bottom_start + y) * st.stride;
uint32_t *src = st.data + (st.corner_size + src_y) * st.stride; d = (uint32_t*)(buf->data.front + y * buf->stride);
uint32_t *left_dest = (uint32_t*)(decs.left.buffer.data.front + dest_y * decs.left.buffer.stride); memcpy(d, src, sizeof(uint32_t) * scaled_shadow_size);
memcpy(left_dest, src, margin * sizeof(uint32_t));
src += 2 * st.corner_size; buf = &decs.shadow_lower_right.buffer;
uint32_t *right_dest = (uint32_t*)(decs.right.buffer.data.front + dest_y * decs.right.buffer.stride); src += st.stride - scaled_shadow_size;
memcpy(right_dest, src, margin * sizeof(uint32_t)); d = (uint32_t*)(buf->data.front + y * buf->stride);
memcpy(d, src, sizeof(uint32_t) * scaled_shadow_size);
render_horizontal_shadow(window, scaled_shadow_size, 0, y, &decs.shadow_top.buffer);
render_horizontal_shadow(window, scaled_shadow_size, st.stride - scaled_shadow_size, y, &decs.shadow_bottom.buffer);
} }
// side shadows
// top region
const ssize_t src_leftover_corner = st.corner_size - scaled_shadow_size;
ssize_t y_start = 0, y_end = decs.shadow_left.buffer.height, top_end = MIN(y_end, src_leftover_corner);
ssize_t right_src_start = st.stride - scaled_shadow_size;
#define c(src_y_start, src_y_limit, dest_y_start, dest_y_limit) { \
copy_vertical_region(window, src_y_start, src_y_limit, dest_y_start, dest_y_limit, 0, &decs.shadow_left.buffer); \
copy_vertical_region(window, src_y_start, src_y_limit, dest_y_start, dest_y_limit, right_src_start, &decs.shadow_right.buffer); \
}
c(scaled_shadow_size, st.corner_size, y_start, top_end);
// bottom region
ssize_t bottom_start = MAX(0, y_end - src_leftover_corner);
c(st.stride - st.corner_size, st.stride - scaled_shadow_size, bottom_start, y_end);
// middle region
for (ssize_t dest_y = top_end; dest_y < bottom_start; dest_y += scaled_shadow_size)
c(st.corner_size, st.corner_size + scaled_shadow_size, dest_y, MIN(dest_y + scaled_shadow_size, bottom_start));
#undef c
#define copy(which) for (uint32_t *src = (uint32_t*)decs.which.buffer.data.front, *dest = (uint32_t*)decs.which.buffer.data.back; src < (uint32_t*)(decs.which.buffer.data.front + decs.which.buffer.size_in_bytes); src++, dest++) *dest = (A(*src) / 2 ) << 24; #define copy(which) for (uint32_t *src = (uint32_t*)decs.which.buffer.data.front, *dest = (uint32_t*)decs.which.buffer.data.back; src < (uint32_t*)(decs.which.buffer.data.front + decs.which.buffer.size_in_bytes); src++, dest++) *dest = (A(*src) / 2 ) << 24;
copy(left); copy(bottom); copy(right); all_shadow_surfaces(copy);
#undef copy #undef copy
} }
@@ -302,14 +309,18 @@ static bool
create_shm_buffers(_GLFWwindow* window) { create_shm_buffers(_GLFWwindow* window) {
const float scale = _glfwWaylandWindowScale(window); const float scale = _glfwWaylandWindowScale(window);
const size_t vertical_width = decs.metrics.width, vertical_height = window->wl.height + decs.metrics.top;
const size_t horizontal_height = decs.metrics.width, horizontal_width = window->wl.width + 2 * decs.metrics.width;
decs.mapping.size = 0; decs.mapping.size = 0;
decs.mapping.size += init_buffer_pair(&decs.top.buffer, window->wl.width, decs.metrics.top, scale); #define bp(which, width, height) decs.mapping.size += init_buffer_pair(&decs.which.buffer, width, height, scale);
decs.mapping.size += init_buffer_pair(&decs.left.buffer, vertical_width, vertical_height, scale); bp(titlebar, window->wl.width, decs.metrics.visible_titlebar_height);
decs.mapping.size += init_buffer_pair(&decs.bottom.buffer, horizontal_width, horizontal_height, scale); bp(shadow_top, window->wl.width, decs.metrics.width);
decs.mapping.size += init_buffer_pair(&decs.right.buffer, vertical_width, vertical_height, scale); bp(shadow_bottom, window->wl.width, decs.metrics.width);
bp(shadow_left, decs.metrics.width, window->wl.height + decs.metrics.visible_titlebar_height);
bp(shadow_right, decs.metrics.width, window->wl.height + decs.metrics.visible_titlebar_height);
bp(shadow_upper_left, decs.metrics.width, decs.metrics.width);
bp(shadow_upper_right, decs.metrics.width, decs.metrics.width);
bp(shadow_lower_left, decs.metrics.width, decs.metrics.width);
bp(shadow_lower_right, decs.metrics.width, decs.metrics.width);
#undef bp
int fd = createAnonymousFile(decs.mapping.size); int fd = createAnonymousFile(decs.mapping.size);
if (fd < 0) { if (fd < 0) {
@@ -326,20 +337,20 @@ create_shm_buffers(_GLFWwindow* window) {
struct wl_shm_pool* pool = wl_shm_create_pool(_glfw.wl.shm, fd, decs.mapping.size); struct wl_shm_pool* pool = wl_shm_create_pool(_glfw.wl.shm, fd, decs.mapping.size);
close(fd); close(fd);
size_t offset = 0; size_t offset = 0;
#define a(which) alloc_buffer_pair(window->id, &decs.which.buffer, pool, decs.mapping.data, &offset) #define Q(which) alloc_buffer_pair(window->id, &decs.which.buffer, pool, decs.mapping.data, &offset)
a(top); a(left); a(bottom); a(right); all_surfaces(Q);
#undef a #undef Q
wl_shm_pool_destroy(pool); wl_shm_pool_destroy(pool);
create_shadow_tile(window); create_shadow_tile(window);
render_title_bar(window, true); render_title_bar(window, true);
render_edges(window); render_shadows(window);
debug("Created decoration buffers at scale: %f vertical_height: %zu horizontal_width: %zu\n", scale, vertical_height, horizontal_width); debug("Created decoration buffers at scale: %f\n", scale);
return true; return true;
} }
static void static void
free_csd_surfaces(_GLFWwindow *window) { free_csd_surfaces(_GLFWwindow *window) {
#define d(which) {\ #define Q(which) {\
if (decs.which.subsurface) wl_subsurface_destroy(decs.which.subsurface); \ if (decs.which.subsurface) wl_subsurface_destroy(decs.which.subsurface); \
decs.which.subsurface = NULL; \ decs.which.subsurface = NULL; \
if (decs.which.surface) wl_surface_destroy(decs.which.surface); \ if (decs.which.surface) wl_surface_destroy(decs.which.surface); \
@@ -347,33 +358,34 @@ free_csd_surfaces(_GLFWwindow *window) {
if (decs.which.wp_viewport) wp_viewport_destroy(decs.which.wp_viewport); \ if (decs.which.wp_viewport) wp_viewport_destroy(decs.which.wp_viewport); \
decs.which.wp_viewport = NULL; \ decs.which.wp_viewport = NULL; \
} }
d(left); d(top); d(right); d(bottom); all_surfaces(Q);
#undef d #undef Q
} }
static void static void
free_csd_buffers(_GLFWwindow *window) { free_csd_buffers(_GLFWwindow *window) {
#define d(which) { \ #define Q(which) { \
if (decs.which.buffer.a_needs_to_be_destroyed && decs.which.buffer.a) wl_buffer_destroy(decs.which.buffer.a); \ if (decs.which.buffer.a_needs_to_be_destroyed && decs.which.buffer.a) wl_buffer_destroy(decs.which.buffer.a); \
if (decs.which.buffer.b_needs_to_be_destroyed && decs.which.buffer.b) wl_buffer_destroy(decs.which.buffer.b); \ if (decs.which.buffer.b_needs_to_be_destroyed && decs.which.buffer.b) wl_buffer_destroy(decs.which.buffer.b); \
memset(&decs.which.buffer, 0, sizeof(_GLFWWaylandBufferPair)); \ memset(&decs.which.buffer, 0, sizeof(_GLFWWaylandBufferPair)); \
} }
d(left); d(top); d(right); d(bottom); all_surfaces(Q);
#undef d #undef Q
if (decs.mapping.data) munmap(decs.mapping.data, decs.mapping.size); if (decs.mapping.data) munmap(decs.mapping.data, decs.mapping.size);
decs.mapping.data = NULL; decs.mapping.size = 0; decs.mapping.data = NULL; decs.mapping.size = 0;
} }
static void static void
position_csd_surface(_GLFWWaylandCSDEdge *s, int x, int y) { position_csd_surface(_GLFWWaylandCSDSurface *s, int x, int y) {
wl_surface_set_buffer_scale(s->surface, 1); wl_surface_set_buffer_scale(s->surface, 1);
s->x = x; s->y = y; s->x = x; s->y = y;
wl_subsurface_set_position(s->subsurface, s->x, s->y); wl_subsurface_set_position(s->subsurface, s->x, s->y);
} }
static void static void
create_csd_surfaces(_GLFWwindow *window, _GLFWWaylandCSDEdge *s) { create_csd_surfaces(_GLFWwindow *window, _GLFWWaylandCSDSurface *s) {
s->surface = wl_compositor_create_surface(_glfw.wl.compositor); s->surface = wl_compositor_create_surface(_glfw.wl.compositor);
wl_surface_set_user_data(s->surface, window);
s->subsurface = wl_subcompositor_get_subsurface(_glfw.wl.subcompositor, s->surface, window->wl.surface); s->subsurface = wl_subcompositor_get_subsurface(_glfw.wl.subcompositor, s->surface, window->wl.surface);
if (_glfw.wl.wp_viewporter) s->wp_viewport = wp_viewporter_get_viewport(_glfw.wl.wp_viewporter, s->surface); if (_glfw.wl.wp_viewporter) s->wp_viewport = wp_viewporter_get_viewport(_glfw.wl.wp_viewporter, s->surface);
} }
@@ -401,7 +413,7 @@ ensure_csd_resources(_GLFWwindow *window) {
decs.for_window_state.fscale != _glfwWaylandWindowScale(window) || decs.for_window_state.fscale != _glfwWaylandWindowScale(window) ||
!decs.mapping.data !decs.mapping.data
); );
const bool needs_update = focus_changed || size_changed || !decs.left.surface || decs.buffer_destroyed; const bool needs_update = focus_changed || size_changed || !decs.titlebar.surface || decs.buffer_destroyed;
debug("CSD: old.size: %dx%d new.size: %dx%d needs_update: %d size_changed: %d buffer_destroyed: %d\n", debug("CSD: old.size: %dx%d new.size: %dx%d needs_update: %d size_changed: %d buffer_destroyed: %d\n",
decs.for_window_state.width, decs.for_window_state.height, window->wl.width, window->wl.height, needs_update, size_changed, decs.buffer_destroyed); decs.for_window_state.width, decs.for_window_state.height, window->wl.width, window->wl.height, needs_update, size_changed, decs.buffer_destroyed);
if (!needs_update) return false; if (!needs_update) return false;
@@ -411,28 +423,26 @@ ensure_csd_resources(_GLFWwindow *window) {
decs.buffer_destroyed = false; decs.buffer_destroyed = false;
} }
int32_t x, y; #define setup_surface(which, x, y) \
x = 0; y = -decs.metrics.top; if (!decs.which.surface) create_csd_surfaces(window, &decs.which); \
if (!decs.top.surface) create_csd_surfaces(window, &decs.top); position_csd_surface(&decs.which, x, y);
position_csd_surface(&decs.top, x, y);
x = -decs.metrics.width; y = -decs.metrics.top; setup_surface(titlebar, 0, -decs.metrics.visible_titlebar_height);
if (!decs.left.surface) create_csd_surfaces(window, &decs.left); setup_surface(shadow_top, decs.titlebar.x, decs.titlebar.y - decs.metrics.width);
position_csd_surface(&decs.left, x, y); setup_surface(shadow_bottom, decs.titlebar.x, window->wl.height);
setup_surface(shadow_left, -decs.metrics.width, decs.titlebar.y);
x = -decs.metrics.width; y = window->wl.height; setup_surface(shadow_right, window->wl.width, decs.shadow_left.y);
if (!decs.bottom.surface) create_csd_surfaces(window, &decs.bottom); setup_surface(shadow_upper_left, decs.shadow_left.x, decs.shadow_top.y);
position_csd_surface(&decs.bottom, x, y); setup_surface(shadow_upper_right, decs.shadow_right.x, decs.shadow_top.y);
setup_surface(shadow_lower_left, decs.shadow_left.x, decs.shadow_bottom.y);
x = window->wl.width; y = -decs.metrics.top; setup_surface(shadow_lower_right, decs.shadow_right.x, decs.shadow_bottom.y);
if (!decs.right.surface) create_csd_surfaces(window, &decs.right);
position_csd_surface(&decs.right, x, y);
if (focus_changed) update_title_bar(window); if (focus_changed) update_title_bar(window);
damage_csd(top, decs.top.buffer.front); damage_csd(titlebar, decs.titlebar.buffer.front);
damage_csd(left, is_focused ? decs.left.buffer.front : decs.left.buffer.back); #define d(which) damage_csd(which, is_focused ? decs.which.buffer.front : decs.which.buffer.back);
damage_csd(bottom, is_focused ? decs.bottom.buffer.front : decs.bottom.buffer.back); d(shadow_left); d(shadow_right); d(shadow_top); d(shadow_bottom);
damage_csd(right, is_focused ? decs.right.buffer.front : decs.right.buffer.back); d(shadow_upper_left); d(shadow_upper_right); d(shadow_lower_left); d(shadow_lower_right);
#undef d
decs.for_window_state.width = window->wl.width; decs.for_window_state.width = window->wl.width;
decs.for_window_state.height = window->wl.height; decs.for_window_state.height = window->wl.height;
@@ -461,9 +471,9 @@ bool
csd_change_title(_GLFWwindow *window) { csd_change_title(_GLFWwindow *window) {
if (!window_is_csd_capable(window)) return false; if (!window_is_csd_capable(window)) return false;
if (ensure_csd_resources(window)) return true; // CSD were re-rendered for other reasons if (ensure_csd_resources(window)) return true; // CSD were re-rendered for other reasons
if (decs.top.surface) { if (decs.titlebar.surface) {
update_title_bar(window); update_title_bar(window);
damage_csd(top, decs.top.buffer.front); damage_csd(titlebar, decs.titlebar.buffer.front);
return true; return true;
} }
return false; return false;
@@ -471,7 +481,7 @@ csd_change_title(_GLFWwindow *window) {
void void
csd_set_window_geometry(_GLFWwindow *window, int32_t *width, int32_t *height) { csd_set_window_geometry(_GLFWwindow *window, int32_t *width, int32_t *height) {
bool has_csd = window_is_csd_capable(window) && decs.top.surface && !(window->wl.current.toplevel_states & TOPLEVEL_STATE_FULLSCREEN); bool has_csd = window_is_csd_capable(window) && decs.titlebar.surface && !(window->wl.current.toplevel_states & TOPLEVEL_STATE_FULLSCREEN);
bool size_specified_by_compositor = *width > 0 && *height > 0; bool size_specified_by_compositor = *width > 0 && *height > 0;
if (!size_specified_by_compositor) { if (!size_specified_by_compositor) {
*width = window->wl.user_requested_content_size.width; *width = window->wl.user_requested_content_size.width;
@@ -551,17 +561,15 @@ set_cursor(GLFWCursorShape shape, _GLFWwindow* window)
static bool static bool
update_hovered_button(_GLFWwindow *window) { update_hovered_button(_GLFWwindow *window) {
bool has_hovered_button = false; bool has_hovered_button = false;
if (y >= decs.metrics.width) { int scaled_x = (int)round(decs.for_window_state.fscale * x);
int scaled_x = (int)round(decs.for_window_state.fscale * x);
#define c(which) \ #define c(which) \
if (decs.which.left <= scaled_x && scaled_x < decs.which.left + decs.which.width) { \ if (decs.which.left <= scaled_x && scaled_x < decs.which.left + decs.which.width) { \
has_hovered_button = true; \ has_hovered_button = true; \
if (!decs.which.hovered) { decs.titlebar_needs_update = true; decs.which.hovered = true; } \ if (!decs.which.hovered) { decs.titlebar_needs_update = true; decs.which.hovered = true; } \
} else if (decs.which.hovered) { decs.titlebar_needs_update = true; decs.which.hovered = false; } } else if (decs.which.hovered) { decs.titlebar_needs_update = true; decs.which.hovered = false; }
c(minimize); c(maximize); c(close); c(minimize); c(maximize); c(close);
#undef c #undef c
}
update_title_bar(window); update_title_bar(window);
return has_hovered_button; return has_hovered_button;
} }
@@ -572,9 +580,9 @@ has_hovered_button(_GLFWwindow *window) {
} }
static void static void
handle_pointer_leave(_GLFWwindow *window) { handle_pointer_leave(_GLFWwindow *window, struct wl_surface *surface) {
#define c(which) if (decs.which.hovered) { decs.titlebar_needs_update = true; decs.which.hovered = false; } #define c(which) if (decs.which.hovered) { decs.titlebar_needs_update = true; decs.which.hovered = false; }
if (decs.focus == TOP_DECORATION) { if (surface == decs.titlebar.surface) {
c(minimize); c(maximize); c(close); c(minimize); c(maximize); c(close);
} }
#undef c #undef c
@@ -588,38 +596,27 @@ handle_pointer_move(_GLFWwindow *window) {
switch (decs.focus) switch (decs.focus)
{ {
case CENTRAL_WINDOW: break; case CENTRAL_WINDOW: break;
case TOP_DECORATION: case CSD_titlebar: if (update_hovered_button(window)) cursorShape = GLFW_POINTER_CURSOR; break;
if (update_hovered_button(window)) { case CSD_shadow_top: cursorShape = GLFW_N_RESIZE_CURSOR; break;
cursorShape = GLFW_POINTER_CURSOR; case CSD_shadow_bottom: cursorShape = GLFW_S_RESIZE_CURSOR; break;
} else if (y < decs.metrics.width) cursorShape = GLFW_N_RESIZE_CURSOR; case CSD_shadow_left: cursorShape = GLFW_W_RESIZE_CURSOR; break;
break; case CSD_shadow_right: cursorShape = GLFW_E_RESIZE_CURSOR; break;
case LEFT_DECORATION: case CSD_shadow_upper_left: cursorShape = GLFW_NW_RESIZE_CURSOR; break;
if (y < decs.metrics.width) case CSD_shadow_upper_right: cursorShape = GLFW_NE_RESIZE_CURSOR; break;
cursorShape = GLFW_NW_RESIZE_CURSOR; case CSD_shadow_lower_left: cursorShape = GLFW_SW_RESIZE_CURSOR; break;
else case CSD_shadow_lower_right: cursorShape = GLFW_SE_RESIZE_CURSOR; break;
cursorShape = GLFW_W_RESIZE_CURSOR;
break;
case RIGHT_DECORATION:
if (y < decs.metrics.width)
cursorShape = GLFW_NE_RESIZE_CURSOR;
else
cursorShape = GLFW_E_RESIZE_CURSOR;
break;
case BOTTOM_DECORATION:
if (x < decs.metrics.width)
cursorShape = GLFW_SW_RESIZE_CURSOR;
else if (x > window->wl.width + decs.metrics.width)
cursorShape = GLFW_SE_RESIZE_CURSOR;
else
cursorShape = GLFW_S_RESIZE_CURSOR;
break;
} }
if (_glfw.wl.cursorPreviousShape != cursorShape) set_cursor(cursorShape, window); if (_glfw.wl.cursorPreviousShape != cursorShape) set_cursor(cursorShape, window);
} }
static void static void
handle_pointer_enter(_GLFWwindow *window) { handle_pointer_enter(_GLFWwindow *window, struct wl_surface *surface) {
handle_pointer_move(window); // enter is also a move #define Q(which) if (decs.which.surface == surface) { \
decs.focus = CSD_##which; handle_pointer_move(window); return; } // enter is also a move
all_surfaces(Q)
#undef Q
decs.focus = CENTRAL_WINDOW;
} }
static void static void
@@ -628,7 +625,7 @@ handle_pointer_button(_GLFWwindow *window, uint32_t button, uint32_t state) {
if (button == BTN_LEFT) { if (button == BTN_LEFT) {
switch (decs.focus) { switch (decs.focus) {
case CENTRAL_WINDOW: break; case CENTRAL_WINDOW: break;
case TOP_DECORATION: case CSD_titlebar:
if (state == WL_POINTER_BUTTON_STATE_PRESSED) { if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
monotonic_t last_click_at = decs.last_click_on_top_decoration_at; monotonic_t last_click_at = decs.last_click_on_top_decoration_at;
decs.last_click_on_top_decoration_at = monotonic(); decs.last_click_on_top_decoration_at = monotonic();
@@ -648,39 +645,22 @@ handle_pointer_button(_GLFWwindow *window, uint32_t button, uint32_t state) {
} else if (decs.close.hovered) _glfwInputWindowCloseRequest(window); } else if (decs.close.hovered) _glfwInputWindowCloseRequest(window);
} }
if (!has_hovered_button(window)) { if (!has_hovered_button(window)) {
if (y < decs.metrics.width) if (window->wl.xdg.toplevel) xdg_toplevel_move(window->wl.xdg.toplevel, _glfw.wl.seat, _glfw.wl.pointer_serial);
edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP;
else {
if (window->wl.xdg.toplevel)
xdg_toplevel_move(window->wl.xdg.toplevel, _glfw.wl.seat, _glfw.wl.pointer_serial);
}
} }
break; break;
case LEFT_DECORATION: case CSD_shadow_left: edges = XDG_TOPLEVEL_RESIZE_EDGE_LEFT; break;
if (y < decs.metrics.width) case CSD_shadow_upper_left: edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT; break;
edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT; case CSD_shadow_right: edges = XDG_TOPLEVEL_RESIZE_EDGE_RIGHT; break;
else case CSD_shadow_upper_right: edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT; break;
edges = XDG_TOPLEVEL_RESIZE_EDGE_LEFT; case CSD_shadow_top: edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP; break;
break; case CSD_shadow_lower_left: edges = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT; break;
case RIGHT_DECORATION: case CSD_shadow_bottom: edges = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM; break;
if (y < decs.metrics.width) case CSD_shadow_lower_right: edges = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT; break;
edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT;
else
edges = XDG_TOPLEVEL_RESIZE_EDGE_RIGHT;
break;
case BOTTOM_DECORATION:
if (x < decs.metrics.width)
edges = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT;
else if (x > window->wl.width + decs.metrics.width)
edges = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT;
else
edges = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM;
break;
} }
if (edges != XDG_TOPLEVEL_RESIZE_EDGE_NONE) xdg_toplevel_resize(window->wl.xdg.toplevel, _glfw.wl.seat, _glfw.wl.pointer_serial, edges); if (edges != XDG_TOPLEVEL_RESIZE_EDGE_NONE) xdg_toplevel_resize(window->wl.xdg.toplevel, _glfw.wl.seat, _glfw.wl.pointer_serial, edges);
} }
else if (button == BTN_RIGHT) { else if (button == BTN_RIGHT) {
if (decs.focus != CENTRAL_WINDOW && window->wl.xdg.toplevel) if (decs.focus == CSD_titlebar && window->wl.xdg.toplevel)
{ {
if (window->wl.wm_capabilities.window_menu) xdg_toplevel_show_window_menu( if (window->wl.wm_capabilities.window_menu) xdg_toplevel_show_window_menu(
window->wl.xdg.toplevel, _glfw.wl.seat, _glfw.wl.pointer_serial, (int32_t)x, (int32_t)y - decs.metrics.top); window->wl.xdg.toplevel, _glfw.wl.seat, _glfw.wl.pointer_serial, (int32_t)x, (int32_t)y - decs.metrics.top);
@@ -693,13 +673,13 @@ handle_pointer_button(_GLFWwindow *window, uint32_t button, uint32_t state) {
void void
csd_handle_pointer_event(_GLFWwindow *window, int button, int state) { csd_handle_pointer_event(_GLFWwindow *window, int button, int state, struct wl_surface *surface) {
if (!window_is_csd_capable(window)) return; if (!window_is_csd_capable(window)) return;
decs.titlebar_needs_update = false; decs.titlebar_needs_update = false;
switch (button) { switch (button) {
case -1: handle_pointer_move(window); break; case -1: handle_pointer_move(window); break;
case -2: handle_pointer_enter(window); break; case -2: handle_pointer_enter(window, surface); break;
case -3: handle_pointer_leave(window); break; case -3: handle_pointer_leave(window, surface); break;
default: handle_pointer_button(window, button, state); break; default: handle_pointer_button(window, button, state); break;
} }
if (decs.titlebar_needs_update) { if (decs.titlebar_needs_update) {

View File

@@ -14,4 +14,4 @@ bool csd_change_title(_GLFWwindow *window);
void csd_set_window_geometry(_GLFWwindow *window, int32_t *width, int32_t *height); void csd_set_window_geometry(_GLFWwindow *window, int32_t *width, int32_t *height);
bool csd_set_titlebar_color(_GLFWwindow *window, uint32_t color, bool use_system_color); bool csd_set_titlebar_color(_GLFWwindow *window, uint32_t color, bool use_system_color);
void csd_set_visible(_GLFWwindow *window, bool visible); void csd_set_visible(_GLFWwindow *window, bool visible);
void csd_handle_pointer_event(_GLFWwindow *window, int button, int state); void csd_handle_pointer_event(_GLFWwindow *window, int button, int state, struct wl_surface* surface);

88
glfw/wl_init.c vendored
View File

@@ -62,48 +62,38 @@ static int min(int n1, int n2)
return n1 < n2 ? n1 : n2; return n1 < n2 ? n1 : n2;
} }
static _GLFWwindow*
findWindowFromDecorationSurface(struct wl_surface* surface, _GLFWdecorationSideWayland* which)
{
_GLFWdecorationSideWayland focus;
if (!which) which = &focus;
_GLFWwindow* window = _glfw.windowListHead;
#define q(edge, result) if (surface == window->wl.decorations.edge.surface) { *which = result; break; }
while (window) {
q(top, TOP_DECORATION);
q(left, LEFT_DECORATION);
q(right, RIGHT_DECORATION);
q(bottom, BOTTOM_DECORATION);
window = window->next;
}
#undef q
return window;
}
#define x window->wl.allCursorPosX #define x window->wl.allCursorPosX
#define y window->wl.allCursorPosY #define y window->wl.allCursorPosY
static _GLFWwindow*
get_window_from_surface(struct wl_surface* surface) {
if (!surface) return NULL;
_GLFWwindow *ans = wl_surface_get_user_data(surface);
if (ans) {
const _GLFWwindow *w = _glfw.windowListHead;
while (w) {
if (w == ans) return ans;
w = w->next;
}
}
return NULL;
}
static void static void
pointerHandleEnter( pointerHandleEnter(
void* data UNUSED, struct wl_pointer* pointer UNUSED, uint32_t serial, struct wl_surface* surface, void* data UNUSED, struct wl_pointer* pointer UNUSED, uint32_t serial, struct wl_surface* surface,
wl_fixed_t sx, wl_fixed_t sy wl_fixed_t sx, wl_fixed_t sy
) { ) {
// Happens in case we just destroyed the surface. _GLFWwindow* window = get_window_from_surface(surface);
if (!surface) return; if (!window) return;
_GLFWdecorationSideWayland focus = CENTRAL_WINDOW;
_GLFWwindow* window = wl_surface_get_user_data(surface);
if (!window) {
window = findWindowFromDecorationSurface(surface, &focus);
if (!window) return;
}
window->wl.decorations.focus = focus;
_glfw.wl.serial = serial; _glfw.wl.input_serial = serial; _glfw.wl.pointer_serial = serial; _glfw.wl.pointer_enter_serial = serial; _glfw.wl.serial = serial; _glfw.wl.input_serial = serial; _glfw.wl.pointer_serial = serial; _glfw.wl.pointer_enter_serial = serial;
_glfw.wl.pointerFocus = window; _glfw.wl.pointerFocus = window;
window->wl.allCursorPosX = wl_fixed_to_double(sx); window->wl.allCursorPosX = wl_fixed_to_double(sx);
window->wl.allCursorPosY = wl_fixed_to_double(sy); window->wl.allCursorPosY = wl_fixed_to_double(sy);
if (focus != CENTRAL_WINDOW) csd_handle_pointer_event(window, -2, -2); if (surface != window->wl.surface) {
else { csd_handle_pointer_event(window, -2, -2, surface);
} else {
window->wl.decorations.focus = CENTRAL_WINDOW;
window->wl.hovered = true; window->wl.hovered = true;
window->wl.cursorPosX = x; window->wl.cursorPosX = x;
window->wl.cursorPosY = y; window->wl.cursorPosY = y;
@@ -114,35 +104,32 @@ pointerHandleEnter(
} }
static void static void
pointerHandleLeave(void* data UNUSED, struct wl_pointer* pointer UNUSED, uint32_t serial, struct wl_surface* surface UNUSED) { pointerHandleLeave(void* data UNUSED, struct wl_pointer* pointer UNUSED, uint32_t serial, struct wl_surface* surface) {
_GLFWwindow* window = _glfw.wl.pointerFocus; _GLFWwindow* window = _glfw.wl.pointerFocus;
if (!window) return; if (!window) return;
_glfw.wl.serial = serial; _glfw.wl.serial = serial;
_glfw.wl.pointerFocus = NULL; _glfw.wl.pointerFocus = NULL;
if (window->wl.decorations.focus == CENTRAL_WINDOW) { if (window->wl.surface == surface) {
window->wl.hovered = false; window->wl.hovered = false;
_glfwInputCursorEnter(window, false); _glfwInputCursorEnter(window, false);
_glfw.wl.cursorPreviousShape = GLFW_INVALID_CURSOR; _glfw.wl.cursorPreviousShape = GLFW_INVALID_CURSOR;
} else csd_handle_pointer_event(window, -3, -3); } else csd_handle_pointer_event(window, -3, -3, surface);
} }
static void static void
pointerHandleMotion(void* data UNUSED, struct wl_pointer* pointer UNUSED, uint32_t time UNUSED, wl_fixed_t sx, wl_fixed_t sy) { pointerHandleMotion(void* data UNUSED, struct wl_pointer* pointer UNUSED, uint32_t time UNUSED, wl_fixed_t sx, wl_fixed_t sy) {
_GLFWwindow* window = _glfw.wl.pointerFocus; _GLFWwindow* window = _glfw.wl.pointerFocus;
if (!window) return; if (!window || window->cursorMode == GLFW_CURSOR_DISABLED) return;
if (window->cursorMode == GLFW_CURSOR_DISABLED) return;
window->wl.allCursorPosX = wl_fixed_to_double(sx); window->wl.allCursorPosX = wl_fixed_to_double(sx);
window->wl.allCursorPosY = wl_fixed_to_double(sy); window->wl.allCursorPosY = wl_fixed_to_double(sy);
if (window->wl.decorations.focus != CENTRAL_WINDOW) { if (window->wl.decorations.focus != CENTRAL_WINDOW) {
csd_handle_pointer_event(window, -1, -1); csd_handle_pointer_event(window, -1, -1, NULL);
return; } else {
window->wl.cursorPosX = x;
window->wl.cursorPosY = y;
_glfwInputCursorPos(window, x, y);
_glfw.wl.cursorPreviousShape = GLFW_INVALID_CURSOR;
} }
window->wl.cursorPosX = x;
window->wl.cursorPosY = y;
_glfwInputCursorPos(window, x, y);
_glfw.wl.cursorPreviousShape = GLFW_INVALID_CURSOR;
} }
static void pointerHandleButton(void* data UNUSED, static void pointerHandleButton(void* data UNUSED,
@@ -157,7 +144,7 @@ static void pointerHandleButton(void* data UNUSED,
_GLFWwindow* window = _glfw.wl.pointerFocus; _GLFWwindow* window = _glfw.wl.pointerFocus;
if (!window) return; if (!window) return;
if (window->wl.decorations.focus != CENTRAL_WINDOW) { if (window->wl.decorations.focus != CENTRAL_WINDOW) {
csd_handle_pointer_event(window, button, state); csd_handle_pointer_event(window, button, state, NULL);
return; return;
} }
/* Makes left, right and middle 0, 1 and 2. Overall order follows evdev /* Makes left, right and middle 0, 1 and 2. Overall order follows evdev
@@ -292,17 +279,8 @@ static void keyboardHandleEnter(void* data UNUSED,
struct wl_surface* surface, struct wl_surface* surface,
struct wl_array* keys) struct wl_array* keys)
{ {
// Happens in the case we just destroyed the surface. _GLFWwindow* window = get_window_from_surface(surface);
if (!surface) if (!window) return;
return;
_GLFWwindow* window = wl_surface_get_user_data(surface);
if (!window)
{
window = findWindowFromDecorationSurface(surface, NULL);
if (!window)
return;
}
_glfw.wl.serial = serial; _glfw.wl.input_serial = serial; _glfw.wl.keyboard_enter_serial = serial; _glfw.wl.serial = serial; _glfw.wl.input_serial = serial; _glfw.wl.keyboard_enter_serial = serial;
_glfw.wl.keyboardFocusId = window->id; _glfw.wl.keyboardFocusId = window->id;

20
glfw/wl_platform.h vendored
View File

@@ -94,14 +94,11 @@ typedef void (* PFN_wl_egl_window_resize)(struct wl_egl_window*, int, int, int,
#define wl_egl_window_destroy _glfw.wl.egl.window_destroy #define wl_egl_window_destroy _glfw.wl.egl.window_destroy
#define wl_egl_window_resize _glfw.wl.egl.window_resize #define wl_egl_window_resize _glfw.wl.egl.window_resize
typedef enum _GLFWdecorationSideWayland typedef enum _GLFWCSDSurface
{ {
CENTRAL_WINDOW, CENTRAL_WINDOW, CSD_titlebar, CSD_shadow_top, CSD_shadow_left, CSD_shadow_bottom, CSD_shadow_right,
TOP_DECORATION, CSD_shadow_upper_left, CSD_shadow_upper_right, CSD_shadow_lower_left, CSD_shadow_lower_right,
LEFT_DECORATION, } _GLFWCSDSurface;
RIGHT_DECORATION,
BOTTOM_DECORATION,
} _GLFWdecorationSideWayland;
typedef struct _GLFWWaylandBufferPair { typedef struct _GLFWWaylandBufferPair {
struct wl_buffer *a, *b, *front, *back; struct wl_buffer *a, *b, *front, *back;
@@ -111,13 +108,13 @@ typedef struct _GLFWWaylandBufferPair {
bool a_needs_to_be_destroyed, b_needs_to_be_destroyed; bool a_needs_to_be_destroyed, b_needs_to_be_destroyed;
} _GLFWWaylandBufferPair; } _GLFWWaylandBufferPair;
typedef struct _GLFWWaylandCSDEdge { typedef struct _GLFWWaylandCSDSurface {
struct wl_surface *surface; struct wl_surface *surface;
struct wl_subsurface *subsurface; struct wl_subsurface *subsurface;
struct wp_viewport *wp_viewport; struct wp_viewport *wp_viewport;
_GLFWWaylandBufferPair buffer; _GLFWWaylandBufferPair buffer;
int x, y; int x, y;
} _GLFWWaylandCSDEdge; } _GLFWWaylandCSDSurface;
typedef enum WaylandWindowState { typedef enum WaylandWindowState {
@@ -203,8 +200,9 @@ typedef struct _GLFWwindowWayland
struct { struct {
bool serverSide, buffer_destroyed, titlebar_needs_update; bool serverSide, buffer_destroyed, titlebar_needs_update;
_GLFWdecorationSideWayland focus; _GLFWCSDSurface focus;
_GLFWWaylandCSDEdge top, left, right, bottom;
_GLFWWaylandCSDSurface titlebar, shadow_left, shadow_right, shadow_top, shadow_bottom, shadow_upper_left, shadow_upper_right, shadow_lower_left, shadow_lower_right;
struct { struct {
uint8_t *data; uint8_t *data;