From e0498157b9000f70f266832c795b46b31df1ec69 Mon Sep 17 00:00:00 2001 From: Allen Webster Date: Sat, 28 Feb 2026 11:34:43 -0800 Subject: [PATCH] [digesting_libdecor] swap out with fixed component indexes --- digesting_libdecor.c | 638 ++++++++++++++++--------------------------- digesting_libdecor.h | 72 ++--- 2 files changed, 269 insertions(+), 441 deletions(-) diff --git a/digesting_libdecor.c b/digesting_libdecor.c index 358f8c8..6bb6daf 100755 --- a/digesting_libdecor.c +++ b/digesting_libdecor.c @@ -105,8 +105,8 @@ pointer_enter(void *data, struct wl_pointer *wl_pointer, uint32_t serial, seat->pointer_focus = surface; if (own_proxy(surface)){ - ctx.active = border_component_from_wl_surface(surface); - if (ctx.active){ + ctx.active = component_slot_from_wl_surface(surface); + if (ctx.active != 0){ draw_decoration(); wl_surface_commit(ctx.wl_surface); } @@ -116,15 +116,10 @@ pointer_enter(void *data, struct wl_pointer *wl_pointer, uint32_t serial, struct wl_cursor_image *image = seat->current_cursor->images[0]; struct wl_buffer *buffer = wl_cursor_image_get_buffer(image); wl_surface_attach(seat->cursor_surface, buffer, 0, 0); - wl_surface_set_buffer_scale(seat->cursor_surface, seat->cursor_scale); - wl_surface_damage_buffer(seat->cursor_surface, 0, 0, - image->width * seat->cursor_scale, - image->height * seat->cursor_scale); + wl_surface_set_buffer_scale(seat->cursor_surface, 1); + wl_surface_damage_buffer(seat->cursor_surface, 0, 0, image->width, image->height); wl_surface_commit(seat->cursor_surface); - wl_pointer_set_cursor(seat->wl_pointer, seat->serial, - seat->cursor_surface, - image->hotspot_x / seat->cursor_scale, - image->hotspot_y / seat->cursor_scale); + wl_pointer_set_cursor(seat->wl_pointer, seat->serial, seat->cursor_surface, image->hotspot_x, image->hotspot_y); } } } @@ -162,20 +157,15 @@ pointer_motion(void *data, struct wl_pointer *wl_pointer, uint32_t time, struct wl_cursor_image *image = seat->current_cursor->images[0]; struct wl_buffer *buffer = wl_cursor_image_get_buffer(image); wl_surface_attach(seat->cursor_surface, buffer, 0, 0); - wl_surface_set_buffer_scale(seat->cursor_surface, seat->cursor_scale); - wl_surface_damage_buffer(seat->cursor_surface, 0, 0, - image->width * seat->cursor_scale, - image->height * seat->cursor_scale); + wl_surface_set_buffer_scale(seat->cursor_surface, 1); + wl_surface_damage_buffer(seat->cursor_surface, 0, 0, image->width, image->height); wl_surface_commit(seat->cursor_surface); - wl_pointer_set_cursor(seat->wl_pointer, seat->serial, - seat->cursor_surface, - image->hotspot_x / seat->cursor_scale, - image->hotspot_y / seat->cursor_scale); + wl_pointer_set_cursor(seat->wl_pointer, seat->serial, seat->cursor_surface, image->hotspot_x, image->hotspot_y); } } /* avoid warnings after decoration has been turned off */ - if (!GTK_IS_WIDGET(ctx.header) || ctx.active->type != HEADER){ + if (!GTK_IS_WIDGET(ctx.header) || ctx.active != COMPONENT_SLOT_HEADER){ ctx.hdr_focus.type = HEADER_NONE; } @@ -191,18 +181,14 @@ pointer_motion(void *data, struct wl_pointer *wl_pointer, uint32_t time, draw_title_bar(); wl_surface_commit(ctx.wl_surface); - switch (ctx.titlebar_gesture.state) { - case TITLEBAR_GESTURE_STATE_BUTTON_PRESSED: + if (ctx.titlebar_gesture.state == TITLEBAR_GESTURE_STATE_BUTTON_PRESSED){ if (ctx.titlebar_gesture.first_pressed_button == BTN_LEFT){ - if (ABS((double)seat->pointer_x - (double)ctx.titlebar_gesture.pressed_x) > ctx.drag_threshold || - ABS((double)seat->pointer_y - (double)ctx.titlebar_gesture.pressed_y) > ctx.drag_threshold){ - xdg_toplevel_move(ctx.xdg_toplevel, seat->wl_seat, ctx.titlebar_gesture.pressed_serial); + int xd = ABS(seat->pointer_x - ctx.titlebar_gesture.pressed_x); + int yd = ABS(seat->pointer_y - ctx.titlebar_gesture.pressed_y); + if (xd > ctx.drag_threshold || yd > ctx.drag_threshold){ + xdg_toplevel_move(ctx.xdg_toplevel, seat->wl_seat, ctx.titlebar_gesture.serial); } } - case TITLEBAR_GESTURE_STATE_INIT: - case TITLEBAR_GESTURE_STATE_CONSUMED: - case TITLEBAR_GESTURE_STATE_DISCARDED: - break; } } } @@ -212,17 +198,16 @@ pointer_button(void *data, struct wl_pointer *wl_pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t state){ struct seat *seat = data; if (seat->pointer_focus && own_proxy(seat->pointer_focus)){ - switch (ctx.active->type) { - case SHADOW: { - enum libdecor_resize_edge edge = - component_edge(ctx.active, seat->pointer_x, seat->pointer_y, SHADOW_MARGIN); + switch (ctx.active){ + case COMPONENT_SLOT_SHADOW: { + enum libdecor_resize_edge edge = component_edge(COMPONENT_SLOT_SHADOW, seat->pointer_x, seat->pointer_y); if (edge != LIBDECOR_RESIZE_EDGE_NONE && (ctx.frame_capabilities & LIBDECOR_ACTION_RESIZE)){ - libdecor_frame_resize(seat->wl_seat, serial, edge); + xdg_toplevel_resize(ctx.xdg_toplevel, seat->wl_seat, serial, xdg_edge_from_edge(edge)); } }break; - case HEADER: { + case COMPONENT_SLOT_HEADER: { switch (ctx.titlebar_gesture.state){ case TITLEBAR_GESTURE_STATE_INIT: { if (state == WL_POINTER_BUTTON_STATE_PRESSED){ @@ -245,7 +230,7 @@ pointer_button(void *data, struct wl_pointer *wl_pointer, uint32_t serial, ctx.titlebar_gesture.first_pressed_time = time; ctx.titlebar_gesture.pressed_x = seat->pointer_x; ctx.titlebar_gesture.pressed_y = seat->pointer_y; - ctx.titlebar_gesture.pressed_serial = serial; + ctx.titlebar_gesture.serial = serial; ctx.titlebar_gesture.state = TITLEBAR_GESTURE_STATE_BUTTON_PRESSED; } } @@ -361,7 +346,7 @@ touch_down(void *data, struct wl_touch *wl_touch, uint32_t serial, if (surface != 0 && own_proxy(surface)){ seat->touch_focus = surface; - ctx.touch_active = border_component_from_wl_surface(surface); + ctx.touch_active = component_slot_from_wl_surface(surface); if (ctx.touch_active){ update_touch_focus(seat, x, y); @@ -370,13 +355,16 @@ touch_down(void *data, struct wl_touch *wl_touch, uint32_t serial, draw_decoration(); wl_surface_commit(ctx.wl_surface); - enum libdecor_resize_edge edge = LIBDECOR_RESIZE_EDGE_NONE; - switch (ctx.touch_active->type) { - case SHADOW: { - edge = component_edge(ctx.touch_active, wl_fixed_to_int(x), wl_fixed_to_int(y), SHADOW_MARGIN); + switch (ctx.touch_active){ + case COMPONENT_SLOT_SHADOW: { + enum libdecor_resize_edge edge = component_edge(COMPONENT_SLOT_SHADOW, wl_fixed_to_int(x), wl_fixed_to_int(y)); + if (edge != LIBDECOR_RESIZE_EDGE_NONE && + (ctx.frame_capabilities & LIBDECOR_ACTION_RESIZE)){ + xdg_toplevel_resize(ctx.xdg_toplevel, seat->wl_seat, serial, xdg_edge_from_edge(edge)); + } }break; - case HEADER: { + case COMPONENT_SLOT_HEADER: { switch (ctx.hdr_focus.type){ case HEADER_MIN: case HEADER_MAX: @@ -405,10 +393,6 @@ touch_down(void *data, struct wl_touch *wl_touch, uint32_t serial, default: break; } - if (edge != LIBDECOR_RESIZE_EDGE_NONE && - (ctx.frame_capabilities & LIBDECOR_ACTION_RESIZE)) { - libdecor_frame_resize(seat->wl_seat, serial, edge); - } } } } @@ -418,7 +402,7 @@ touch_up(void *data, struct wl_touch *wl_touch, uint32_t serial, uint32_t time, struct seat *seat = data; if (seat->touch_focus && own_proxy(seat->touch_focus)){ if (ctx.touch_active != 0){ - if (ctx.touch_active->type == HEADER){ + if (ctx.touch_active == COMPONENT_SLOT_HEADER){ switch (ctx.hdr_focus.type) { case HEADER_MIN: { if (ctx.frame_capabilities & LIBDECOR_ACTION_MINIMIZE){ @@ -562,7 +546,6 @@ wl_registry_global(void *data, struct wl_registry *wl_registry, } seat = calloc(1, sizeof *seat); - seat->cursor_scale = 1; wl_list_insert(&ctx.seat_list, &seat->link); seat->wl_seat = wl_registry_bind(ctx.wl_registry, name, &wl_seat_interface, 3); wl_seat_add_listener(seat->wl_seat, &seat_listener, seat); @@ -660,17 +643,16 @@ xdg_toplevel_close(void *user_data, struct xdg_toplevel *xdg_toplevel){ #ifdef XDG_TOPLEVEL_CONFIGURE_BOUNDS_SINCE_VERSION static void -xdg_toplevel_configure_bounds(void *user_data, struct xdg_toplevel *xdg_toplevel, int32_t width, int32_t height){ - int left = 0, top = 0, right = 0, bottom = 0; - - if (ctx.visible != 0 && +xdg_toplevel_configure_bounds(void *user_data, struct xdg_toplevel *xdg_toplevel, int32_t w, int32_t h){ + int32_t inner_w = w; + int32_t inner_h = h; + if (ctx.visible && ctx.decoration_mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE){ - libdecor_plugin_gtk_frame_get_border_size(0, &left, &right, &top, &bottom); + Bounds2D border_size = border_size_from_window_state(0); + inner_w -= border_size.x[0] + border_size.x[1]; + inner_h -= border_size.y[0] + border_size.y[1]; } - - width -= left + right; - height -= top + bottom; - // + // event to user (inner_w,inner_h) } #endif @@ -940,8 +922,10 @@ int main(){ zxdg_toplevel_decoration_v1_add_listener(ctx.toplevel_decoration, &xdg_toplevel_decoration_listener, 0); } - ctx.content_limits.min_width = 80; - ctx.content_limits.min_height = 60; + ctx.size_bounds.x[0] = 80; + ctx.size_bounds.y[0] = 60; + ctx.size_bounds.x[1] = (1 << 30); + ctx.size_bounds.y[1] = (1 << 30); xdg_toplevel_set_app_id(ctx.xdg_toplevel, "demo"); xdg_toplevel_set_title(ctx.xdg_toplevel, "Example Window"); @@ -1140,56 +1124,32 @@ int main(){ //#include "libdecor.c" - -static void -constrain_content_size(int *width, int *height){ - const struct libdecor_limits lim = ctx.content_limits; - - if (lim.min_width > 0) - *width = MAX(lim.min_width, *width); - if (lim.max_width > 0) - *width = MIN(*width, lim.max_width); - - if (lim.min_height > 0) - *height = MAX(lim.min_height, *height); - if (lim.max_height > 0) - *height = MIN(*height, lim.max_height); -} - static void frame_get_window_size_for(struct libdecor_state *state, int *window_width, int *window_height){ *window_width = state->content_width; *window_height = state->content_height; - if (ctx.visible && ctx.decoration_mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE){ - int left, right, top, bottom; - libdecor_plugin_gtk_frame_get_border_size(ctx.frame_window_state, &left, &right, &top, &bottom); - *window_width += left + right; - *window_height += top + bottom; + Bounds2D border_size = border_size_from_window_state(ctx.frame_window_state); + *window_width += border_size.x[0] + border_size.x[1]; + *window_height += border_size.y[0] + border_size.y[1]; } } static void -frame_set_window_geometry(int32_t content_width, int32_t content_height){ - int x, y, width, height; +frame_set_window_geometry(int32_t w, int32_t h){ + Extent2D extent = {0}; + extent.w = w; + extent.w = h; - if (ctx.visible != 0 && - ctx.decoration_mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE){ - int left, right, top, bottom; - libdecor_plugin_gtk_frame_get_border_size(ctx.frame_window_state, &left, &right, &top, &bottom); - x = -left; - y = -top; - width = content_width + left + right; - height = content_height + top + bottom; - } - else{ - x = 0; - y = 0; - width = content_width; - height = content_height; + if (ctx.visible && ctx.decoration_mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE){ + Bounds2D border_size = border_size_from_window_state(ctx.frame_window_state); + extent.x = -border_size.x[0]; + extent.y = -border_size.y[0]; + extent.w = w + border_size.x[0] + border_size.x[1]; + extent.h = h + border_size.y[0] + border_size.y[1]; } - xdg_surface_set_window_geometry(ctx.xdg_surface, x, y, width, height); + xdg_surface_set_window_geometry(ctx.xdg_surface, extent.x, extent.y, extent.w, extent.h); } bool @@ -1206,23 +1166,32 @@ libdecor_configuration_get_content_size(struct libdecor_configuration *configura if (ctx.visible != 0 && ctx.decoration_mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE){ - int left, right, top, bottom; - ctx.frame_window_state = configuration->window_state; if (configuration->has_window_state){ - libdecor_plugin_gtk_frame_get_border_size(configuration->window_state, &left, &right, &top, &bottom); + Bounds2D border_size = border_size_from_window_state(configuration->window_state); + *width -= border_size.x[0] + border_size.x[1]; + *height -= border_size.y[0] + border_size.y[1]; } else{ return false; } - - *width -= (left + right); - *height -= (top + bottom); } /* constrain content dimensions manually */ if (!(configuration->window_state & LIBDECOR_WINDOW_STATE_NON_FLOATING)) { - constrain_content_size(width, height); + // TODO(allen): + if (ctx.size_bounds.x[0] > 0){ + *width = MAX(ctx.size_bounds.x[0], *width); + } + if (ctx.size_bounds.x[1] > 0){ + *width = MIN(*width, ctx.size_bounds.x[1]); + } + if (ctx.size_bounds.y[0] > 0){ + *height = MAX(ctx.size_bounds.y[0], *height); + } + if (ctx.size_bounds.y[1] > 0){ + *height = MIN(*height, ctx.size_bounds.y[1]); + } } return true; @@ -1253,7 +1222,7 @@ libdecor_frame_set_visibility(bool visible){ ctx.frame_content_height > 0){ if (ctx.visible != 0 && ctx.decoration_mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE){ - libdecor_plugin_gtk_frame_commit(0, 0); + libdecor_plugin_gtk_frame_commit(); } else{ libdecor_plugin_gtk_frame_free(); @@ -1265,52 +1234,21 @@ libdecor_frame_set_visibility(bool visible){ } } -void -libdecor_frame_translate_coordinate(int content_x, int content_y, int *frame_x, int *frame_y){ - *frame_x = content_x; - *frame_y = content_y; - - if (ctx.visible != 0 && - ctx.decoration_mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE){ - int left, top; - libdecor_plugin_gtk_frame_get_border_size(0, &left, 0, &top, 0); - *frame_x += left; - *frame_y += top; - } -} - -enum xdg_toplevel_resize_edge -edge_to_xdg_edge(enum libdecor_resize_edge edge) -{ +static enum xdg_toplevel_resize_edge +xdg_edge_from_edge(enum libdecor_resize_edge edge){ + enum xdg_toplevel_resize_edge result = XDG_TOPLEVEL_RESIZE_EDGE_NONE; switch (edge) { - case LIBDECOR_RESIZE_EDGE_NONE: - return XDG_TOPLEVEL_RESIZE_EDGE_NONE; - case LIBDECOR_RESIZE_EDGE_TOP: - return XDG_TOPLEVEL_RESIZE_EDGE_TOP; - case LIBDECOR_RESIZE_EDGE_BOTTOM: - return XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM; - case LIBDECOR_RESIZE_EDGE_LEFT: - return XDG_TOPLEVEL_RESIZE_EDGE_LEFT; - case LIBDECOR_RESIZE_EDGE_TOP_LEFT: - return XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT; - case LIBDECOR_RESIZE_EDGE_BOTTOM_LEFT: - return XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT; - case LIBDECOR_RESIZE_EDGE_RIGHT: - return XDG_TOPLEVEL_RESIZE_EDGE_RIGHT; - case LIBDECOR_RESIZE_EDGE_TOP_RIGHT: - return XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT; - case LIBDECOR_RESIZE_EDGE_BOTTOM_RIGHT: - return XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT; + default: case LIBDECOR_RESIZE_EDGE_NONE: break; + case LIBDECOR_RESIZE_EDGE_TOP: result = XDG_TOPLEVEL_RESIZE_EDGE_TOP; break; + case LIBDECOR_RESIZE_EDGE_BOTTOM: result = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM; break; + case LIBDECOR_RESIZE_EDGE_LEFT: result = XDG_TOPLEVEL_RESIZE_EDGE_LEFT; break; + case LIBDECOR_RESIZE_EDGE_TOP_LEFT: result = XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT; break; + case LIBDECOR_RESIZE_EDGE_BOTTOM_LEFT: result = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT; break; + case LIBDECOR_RESIZE_EDGE_RIGHT: result = XDG_TOPLEVEL_RESIZE_EDGE_RIGHT; break; + case LIBDECOR_RESIZE_EDGE_TOP_RIGHT: result = XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT; break; + case LIBDECOR_RESIZE_EDGE_BOTTOM_RIGHT: result = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT; break; } - - abort(); -} - -void -libdecor_frame_resize(struct wl_seat *wl_seat, uint32_t serial, enum libdecor_resize_edge edge){ - enum xdg_toplevel_resize_edge xdg_edge; - xdg_edge = edge_to_xdg_edge(edge); - xdg_toplevel_resize(ctx.xdg_toplevel, wl_seat, serial, xdg_edge); + return(result); } void @@ -1344,20 +1282,20 @@ libdecor_frame_commit(int w, int h, struct libdecor_configuration *configuration * configure event is received, we have to manually set the min/max * limits with the configured content size afterwards. */ if (!(ctx.frame_capabilities & LIBDECOR_ACTION_RESIZE)){ - ctx.content_limits.min_width = ctx.frame_content_width; - ctx.content_limits.min_height = ctx.frame_content_height; - ctx.content_limits.max_width = ctx.frame_content_width; - ctx.content_limits.max_height = ctx.frame_content_height; + ctx.size_bounds.x[0] = ctx.frame_content_width; + ctx.size_bounds.y[0] = ctx.frame_content_height; + ctx.size_bounds.x[1] = ctx.frame_content_width; + ctx.size_bounds.y[1] = ctx.frame_content_height; } - if (ctx.content_limits.min_width > 0 && - ctx.content_limits.min_height > 0){ + if (ctx.size_bounds.x[0] > 0 && + ctx.size_bounds.y[0] > 0){ struct libdecor_state state_min; int win_min_width, win_min_height; - state_min.content_width = ctx.content_limits.min_width; - state_min.content_height = ctx.content_limits.min_height; - state_min.window_state = state.window_state; + state_min.content_width = ctx.size_bounds.x[0]; + state_min.content_height = ctx.size_bounds.y[0]; + state_min.window_state = state.window_state; frame_get_window_size_for(&state_min, &win_min_width, &win_min_height); xdg_toplevel_set_min_size(ctx.xdg_toplevel, win_min_width, win_min_height); @@ -1366,14 +1304,14 @@ libdecor_frame_commit(int w, int h, struct libdecor_configuration *configuration xdg_toplevel_set_min_size(ctx.xdg_toplevel, 0, 0); } - if (ctx.content_limits.max_width > 0 && - ctx.content_limits.max_height > 0){ + if (ctx.size_bounds.x[1] > 0 && + ctx.size_bounds.y[1] > 0){ struct libdecor_state state_max; int win_max_width, win_max_height; - state_max.content_width = ctx.content_limits.max_width; - state_max.content_height = ctx.content_limits.max_height; - state_max.window_state = state.window_state; + state_max.content_width = ctx.size_bounds.x[1]; + state_max.content_height = ctx.size_bounds.y[1]; + state_max.window_state = state.window_state; frame_get_window_size_for(&state_max, &win_max_width, &win_max_height); xdg_toplevel_set_max_size(ctx.xdg_toplevel, win_max_width, win_max_height); @@ -1384,9 +1322,9 @@ libdecor_frame_commit(int w, int h, struct libdecor_configuration *configuration } /* switch between decoration modes */ - if (ctx.visible != 0 && + if (ctx.visible && ctx.decoration_mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE){ - libdecor_plugin_gtk_frame_commit(&state, configuration); + libdecor_plugin_gtk_frame_commit(); } else{ libdecor_plugin_gtk_frame_free(); @@ -1931,8 +1869,8 @@ libdecor_plugin_gtk_frame_free(void){ g_clear_pointer(&ctx.header, gtk_widget_destroy); g_clear_pointer(&ctx.window, gtk_widget_destroy); - free_border_component(&ctx.headerbar); - free_border_component(&ctx.shadow); + free_border_component(&ctx.component_slot[COMPONENT_SLOT_HEADER]); + free_border_component(&ctx.component_slot[COMPONENT_SLOT_SHADOW]); ctx.shadow_showing = false; g_clear_pointer(&ctx.shadow_blur, cairo_surface_destroy); @@ -1949,44 +1887,21 @@ hide_border_component(struct border_component *border_component){ } } -static struct border_component * -border_component_from_wl_surface(const struct wl_surface *surface){ - struct border_component *result = 0; - if (ctx.shadow.wl_surface == surface){ - result = &ctx.shadow; - } - else if (ctx.headerbar.wl_surface == surface){ - result = &ctx.headerbar; +static enum component_slot +component_slot_from_wl_surface(const struct wl_surface *surface){ + enum component_slot result = 0; + for (int i = 1; i < COMPONENT_SLOT_COUNT; i += 1){ + if (ctx.component_slot[i].wl_surface == surface){ + result = i; + break; + } } return(result); } -static void -redraw_scale(struct border_component *cmpnt){ - struct surface_output *surface_output; - int scale = 1; - - bool need_commit = false; - if (cmpnt->wl_surface != 0){ - if (scale != cmpnt->scale){ - cmpnt->scale = scale; - if ((ctx.decoration_type != DECORATION_TYPE_NONE) && - (cmpnt->type != SHADOW || ctx.shadow_showing)){ - draw_border_component(cmpnt); - need_commit = true; - } - } - } - - if (need_commit){ - wl_surface_commit(ctx.wl_surface); - } -} - static void ensure_component(struct border_component *cmpnt){ if (cmpnt->wl_surface == 0){ - cmpnt->scale = 1; cmpnt->wl_surface = wl_compositor_create_surface(ctx.wl_compositor); wl_proxy_set_tag((struct wl_proxy *)cmpnt->wl_surface, &libdecor_gtk_proxy_tag); cmpnt->wl_subsurface = wl_subcompositor_get_subsurface(ctx.wl_subcompositor, cmpnt->wl_surface, ctx.wl_surface); @@ -1997,12 +1912,13 @@ static void ensure_title_bar_surfaces(void){ GtkStyleContext *context_hdr; - ctx.headerbar.type = HEADER; - ctx.headerbar.opaque = false; - ensure_component(&ctx.headerbar); + ctx.component_slot[COMPONENT_SLOT_HEADER].slot = COMPONENT_SLOT_HEADER; + ctx.component_slot[COMPONENT_SLOT_HEADER].opaque = false; + ensure_component(&ctx.component_slot[COMPONENT_SLOT_HEADER]); - if (ctx.shadow.wl_surface){ - wl_subsurface_place_above(ctx.headerbar.wl_subsurface, ctx.shadow.wl_surface); + if (ctx.component_slot[COMPONENT_SLOT_SHADOW].wl_surface){ + wl_subsurface_place_above(ctx.component_slot[COMPONENT_SLOT_HEADER].wl_subsurface, + ctx.component_slot[COMPONENT_SLOT_SHADOW].wl_surface); } if (GTK_IS_WIDGET(ctx.header)){ @@ -2038,7 +1954,7 @@ ensure_title_bar_surfaces(void){ } static Extent2D -extent2d_from_component(enum component component){ +extent2d_from_component_type(enum component_slot slot){ Extent2D result = {0}; int width = ctx.frame_content_width; int height = ctx.frame_content_height; @@ -2048,17 +1964,17 @@ extent2d_from_component(enum component component){ title_height = gtk_widget_get_allocated_height(ctx.header); } - switch (component){ - case NONE: break; + switch (slot){ + default: case COMPONENT_SLOT_NONE: break; - case SHADOW: { + case COMPONENT_SLOT_SHADOW: { result.x = -(int)SHADOW_MARGIN; result.y = -(int)(SHADOW_MARGIN + title_height); result.w = width + 2*SHADOW_MARGIN; result.h = title_height + height + 2*SHADOW_MARGIN; }break; - case HEADER: { + case COMPONENT_SLOT_HEADER: { result.x = 0; result.y = -title_height; result.w = gtk_widget_get_allocated_width(ctx.header); @@ -2217,9 +2133,9 @@ draw_header_button(cairo_t *cr, cairo_surface_t *surface, static void set_component_input_region(struct border_component *border_component){ - if (border_component->type == SHADOW && ctx.shadow_showing){ + if (border_component->slot == COMPONENT_SLOT_SHADOW && ctx.shadow_showing){ struct wl_region *input_region; - Extent2D extent = extent2d_from_component(border_component->type); + Extent2D extent = extent2d_from_component_type(border_component->slot); /* * the input region is the outer surface size minus the inner @@ -2237,19 +2153,17 @@ static void draw_border_component(struct border_component *border_component){ struct buffer *old_buffer; struct buffer *buffer = 0; - int scale = border_component->scale; - enum component component = border_component->type; if (border_component->wl_surface != 0){ - Extent2D extent = extent2d_from_component(component); + Extent2D extent = extent2d_from_component_type(border_component->slot); set_component_input_region(border_component); old_buffer = border_component->buffer; if (old_buffer != 0){ if (!old_buffer->in_use && - old_buffer->buffer_width == extent.w*scale && - old_buffer->buffer_height == extent.h*scale){ + old_buffer->buffer_width == extent.w && + old_buffer->buffer_height == extent.h){ buffer = old_buffer; } else{ @@ -2268,8 +2182,8 @@ draw_border_component(struct border_component *border_component){ void *data; enum wl_shm_format buf_fmt; - buffer_width = width * scale; - buffer_height = height * scale; + buffer_width = width; + buffer_height = height; stride = buffer_width * 4; size = stride * buffer_height; @@ -2292,7 +2206,6 @@ draw_border_component(struct border_component *border_component){ buffer->data_size = size; buffer->width = width; buffer->height = height; - buffer->scale = scale; buffer->buffer_width = buffer_width; buffer->buffer_height = buffer_height; } @@ -2308,12 +2221,12 @@ draw_border_component(struct border_component *border_component){ cairo_surface_t *surface = cairo_image_surface_create_for_data(buffer->data, CAIRO_FORMAT_ARGB32, buffer->buffer_width, buffer->buffer_height, stride); cairo_t *cr = cairo_create(surface); - cairo_surface_set_device_scale(surface, buffer->scale, buffer->scale); + cairo_surface_set_device_scale(surface, 1, 1); - switch (component) { - case NONE: break; + switch (border_component->slot){ + default: case COMPONENT_SLOT_NONE: break; - case SHADOW: { + case COMPONENT_SLOT_SHADOW: { render_shadow(cr, ctx.shadow_blur, -(int)SHADOW_MARGIN/2, -(int)SHADOW_MARGIN/2, buffer->width + SHADOW_MARGIN, buffer->height + SHADOW_MARGIN, @@ -2323,7 +2236,7 @@ draw_border_component(struct border_component *border_component){ cairo_fill(cr); }break; - case HEADER: { + case COMPONENT_SLOT_HEADER: { /* background */ { GtkAllocation allocation; @@ -2381,10 +2294,10 @@ draw_border_component(struct border_component *border_component){ } wl_surface_attach(border_component->wl_surface, buffer->wl_buffer, 0, 0); - wl_surface_set_buffer_scale(border_component->wl_surface, buffer->scale); + wl_surface_set_buffer_scale(border_component->wl_surface, 1); buffer->in_use = true; wl_surface_commit(border_component->wl_surface); - wl_surface_damage_buffer(border_component->wl_surface, 0, 0, extent.w*scale, extent.h*scale); + wl_surface_damage_buffer(border_component->wl_surface, 0, 0, extent.w, extent.h); wl_subsurface_set_position(border_component->wl_subsurface, extent.x, extent.y); border_component->buffer = buffer; @@ -2422,25 +2335,25 @@ draw_title_bar(void){ gtk_header_bar_set_title(GTK_HEADER_BAR(ctx.header), ""); gtk_widget_get_preferred_width(ctx.header, NULL, &pref_width); gtk_header_bar_set_title(GTK_HEADER_BAR(ctx.header), ctx.title); - if (ctx.content_limits.min_width < pref_width){ - ctx.content_limits.min_width = pref_width; + if (ctx.size_bounds.x[0] < pref_width){ + ctx.size_bounds.x[0] = pref_width; } - if (ctx.content_limits.max_width != 0 && - ctx.content_limits.max_width < ctx.content_limits.min_width){ - ctx.content_limits.max_width = ctx.content_limits.min_width; + if (ctx.size_bounds.x[1] != 0 && + ctx.size_bounds.x[1] < ctx.size_bounds.x[0]){ + ctx.size_bounds.x[1] = ctx.size_bounds.x[0]; } W = ctx.frame_content_width; H = ctx.frame_content_height; - if (W < ctx.content_limits.min_width){ - W = ctx.content_limits.min_width; + if (W < ctx.size_bounds.x[0]){ + W = ctx.size_bounds.x[0]; libdecor_frame_commit(W, H, NULL); } else{ /* set default height */ gtk_widget_get_preferred_height(ctx.header, 0, &allocation.height); gtk_widget_size_allocate(ctx.header, &allocation); - draw_border_component(&ctx.headerbar); + draw_border_component(&ctx.component_slot[COMPONENT_SLOT_HEADER]); } } @@ -2448,23 +2361,23 @@ static void draw_decoration(void){ switch (ctx.decoration_type){ case DECORATION_TYPE_NONE: { - hide_border_component(&ctx.shadow); + hide_border_component(&ctx.component_slot[COMPONENT_SLOT_SHADOW]); ctx.shadow_showing = false; - hide_border_component(&ctx.headerbar); + hide_border_component(&ctx.component_slot[COMPONENT_SLOT_HEADER]); }break; case DECORATION_TYPE_ALL: { - ctx.shadow.type = SHADOW; - ctx.shadow.opaque = false; - ensure_component(&ctx.shadow); - draw_border_component(&ctx.shadow); + ctx.component_slot[COMPONENT_SLOT_SHADOW].slot = COMPONENT_SLOT_SHADOW; + ctx.component_slot[COMPONENT_SLOT_SHADOW].opaque = false; + ensure_component(&ctx.component_slot[COMPONENT_SLOT_SHADOW]); + draw_border_component(&ctx.component_slot[COMPONENT_SLOT_SHADOW]); ctx.shadow_showing = true; ensure_title_bar_surfaces(); draw_title_bar(); }break; case DECORATION_TYPE_TITLE_ONLY: { - hide_border_component(&ctx.shadow); + hide_border_component(&ctx.component_slot[COMPONENT_SLOT_SHADOW]); ctx.shadow_showing = false; ensure_title_bar_surfaces(); draw_title_bar(); @@ -2489,7 +2402,7 @@ decoration_type_from_window_state(enum libdecor_window_state window_state){ } static void -libdecor_plugin_gtk_frame_commit(struct libdecor_state *state, struct libdecor_configuration *configuration){ +libdecor_plugin_gtk_frame_commit(void){ enum libdecor_window_state old_window_state; enum libdecor_window_state new_window_state; int old_content_width, old_content_height; @@ -2522,182 +2435,113 @@ libdecor_plugin_gtk_frame_commit(struct libdecor_state *state, struct libdecor_c /* set fixed window size */ if (!(ctx.frame_capabilities & LIBDECOR_ACTION_RESIZE)){ - ctx.content_limits.min_width = ctx.gtk_content_width; - ctx.content_limits.min_height = ctx.gtk_content_height; - ctx.content_limits.max_width = ctx.gtk_content_width; - ctx.content_limits.max_height = ctx.gtk_content_height; + ctx.size_bounds.x[0] = ctx.gtk_content_width; + ctx.size_bounds.y[0] = ctx.gtk_content_height; + ctx.size_bounds.x[1] = ctx.gtk_content_width; + ctx.size_bounds.y[1] = ctx.gtk_content_height; } } } -static void -update_component_focus(struct wl_surface *surface, struct seat *seat){ - static struct border_component *border_component; - static struct border_component *child_component; - static struct border_component *focus_component; - - border_component = border_component_from_wl_surface(surface); - - focus_component = border_component; - wl_list_for_each(child_component, &border_component->child_components, link) { - Extent2D extent = extent2d_from_component(child_component->type); - if (seat->pointer_x >= extent.x && seat->pointer_x < extent.x + extent.w && - seat->pointer_y >= extent.y && seat->pointer_y < extent.y + extent.h) { - focus_component = child_component; - break; - } - } - - if (ctx.grab){ - ctx.active = ctx.grab; - } - else{ - ctx.active = focus_component; - } - ctx.focus = focus_component; -} - -static void -libdecor_plugin_gtk_frame_get_border_size(enum libdecor_window_state window_state, - int *left, int *right, int *top, int *bottom){ - if (left){ - *left = 0; - } - if (right){ - *right = 0; - } - if (bottom){ - *bottom = 0; - } - if (top) { - switch (decoration_type_from_window_state(window_state)) { - case DECORATION_TYPE_NONE: { - *top = 0; - }break; - - case DECORATION_TYPE_ALL: { - ctx.shadow.type = SHADOW; - ctx.shadow.opaque = false; - ensure_component(&ctx.shadow); - } G_GNUC_FALLTHROUGH; - - case DECORATION_TYPE_TITLE_ONLY: { - if (ctx.header == 0){ - ensure_title_bar_surfaces(); - } - gtk_widget_show_all(ctx.window); - gtk_widget_get_preferred_height(ctx.header, NULL, top); - }break; - } +static Bounds2D +border_size_from_window_state(enum libdecor_window_state window_state){ + Bounds2D border_size = {0}; + switch (decoration_type_from_window_state(window_state)) { + case DECORATION_TYPE_NONE: break; + + case DECORATION_TYPE_ALL: { + ctx.component_slot[COMPONENT_SLOT_SHADOW].slot = COMPONENT_SLOT_SHADOW; + ctx.component_slot[COMPONENT_SLOT_SHADOW].opaque = false; + ensure_component(&ctx.component_slot[COMPONENT_SLOT_SHADOW]); + } G_GNUC_FALLTHROUGH; + + case DECORATION_TYPE_TITLE_ONLY: { + if (ctx.header == 0){ + ensure_title_bar_surfaces(); + } + gtk_widget_show_all(ctx.window); + gtk_widget_get_preferred_height(ctx.header, 0, &border_size.y[0]); + }break; } + return(border_size); } enum libdecor_resize_edge -component_edge(const struct border_component *cmpnt, - const int pointer_x, const int pointer_y, - const int margin){ - const bool top = pointer_y < margin * 2; - const bool bottom = pointer_y > (cmpnt->buffer->height - margin * 2); - const bool left = pointer_x < margin * 2; - const bool right = pointer_x > (cmpnt->buffer->width - margin * 2); +component_edge(enum component_slot slot, int x, int y){ + static const enum libdecor_resize_edge box[9] = { + LIBDECOR_RESIZE_EDGE_TOP_LEFT , LIBDECOR_RESIZE_EDGE_TOP , LIBDECOR_RESIZE_EDGE_TOP_RIGHT , + LIBDECOR_RESIZE_EDGE_LEFT, LIBDECOR_RESIZE_EDGE_NONE , LIBDECOR_RESIZE_EDGE_RIGHT , + LIBDECOR_RESIZE_EDGE_BOTTOM_LEFT, LIBDECOR_RESIZE_EDGE_BOTTOM, LIBDECOR_RESIZE_EDGE_BOTTOM_RIGHT, + }; - if (top){ - if (left) - return LIBDECOR_RESIZE_EDGE_TOP_LEFT; - else if (right) - return LIBDECOR_RESIZE_EDGE_TOP_RIGHT; - else - return LIBDECOR_RESIZE_EDGE_TOP; - } - else if (bottom){ - if (left) - return LIBDECOR_RESIZE_EDGE_BOTTOM_LEFT; - else if (right) - return LIBDECOR_RESIZE_EDGE_BOTTOM_RIGHT; - else - return LIBDECOR_RESIZE_EDGE_BOTTOM; - } - else if (left){ - return LIBDECOR_RESIZE_EDGE_LEFT; - } - else if (right){ - return LIBDECOR_RESIZE_EDGE_RIGHT; - } - else{ - return LIBDECOR_RESIZE_EDGE_NONE; - } -} - -static bool -update_local_cursor(struct seat *seat){ - bool result = false; + enum libdecor_resize_edge result = 0; + struct buffer *buffer = 0; - if (seat->pointer_focus == 0){ - seat->current_cursor = seat->cursor_left_ptr; + if (slot < COMPONENT_SLOT_COUNT){ + buffer = ctx.component_slot[slot].buffer; } - else{ - if (own_proxy(seat->pointer_focus)){ - if (!ctx.active){ - seat->current_cursor = seat->cursor_left_ptr; - } - else{ - bool theme_updated = false; - { - int scale = 1; - if (seat->cursor_theme == 0 || seat->cursor_scale != scale){ - struct wl_cursor_theme *theme; - - seat->cursor_scale = scale; - theme = wl_cursor_theme_load(ctx.cursor_theme_name, ctx.cursor_size*scale, ctx.wl_shm); - if (theme != 0){ - if (seat->cursor_theme){ - wl_cursor_theme_destroy(seat->cursor_theme); - } - - seat->cursor_theme = theme; - - for (unsigned int i = 0; i < ARRAY_LENGTH(cursor_names); i++) { - seat->cursors[i] = wl_cursor_theme_get_cursor(seat->cursor_theme, cursor_names[i]); - } - - seat->cursor_left_ptr = wl_cursor_theme_get_cursor(seat->cursor_theme, "left_ptr"); - seat->current_cursor = seat->cursor_left_ptr; - theme_updated = true; - } - } - } - - struct wl_cursor *wl_cursor = NULL; - if (ctx.active->type == SHADOW && ctx.shadow_showing && - (ctx.frame_capabilities & LIBDECOR_ACTION_RESIZE)){ - enum libdecor_resize_edge edge; - edge = component_edge(ctx.active, seat->pointer_x, seat->pointer_y, SHADOW_MARGIN); - if (edge != LIBDECOR_RESIZE_EDGE_NONE){ - wl_cursor = seat->cursors[edge - 1]; - } - } - else{ - wl_cursor = seat->cursor_left_ptr; - } - - if (seat->current_cursor != wl_cursor) { - seat->current_cursor = wl_cursor; - result = true; - } - else{ - result = theme_updated; - } - } - } + + if (buffer != 0){ + int w = buffer->width; + int h = buffer->height; + + int top = (y < 2*SHADOW_MARGIN); + int bottom = (!top && y > (w - 2*SHADOW_MARGIN)); + int left = (x < 2*SHADOW_MARGIN); + int right = (!left && x > (h - 2*SHADOW_MARGIN)); + + int i = 4 + 3*(bottom - top) + (right - left); + result = box[i]; } return(result); } +static bool +update_local_cursor(struct seat *seat){ + bool cursor_updated = false; + + seat->current_cursor = seat->cursor_left_ptr; + if (own_proxy(seat->pointer_focus)){ + if (ctx.active != 0){ + if (seat->cursor_theme == 0){ + struct wl_cursor_theme *theme = wl_cursor_theme_load(ctx.cursor_theme_name, ctx.cursor_size, ctx.wl_shm); + if (theme != 0){ + seat->cursor_theme = theme; + + for (unsigned int i = 0; i < ARRAY_LENGTH(cursor_names); i += 1){ + seat->cursors[i] = wl_cursor_theme_get_cursor(theme, cursor_names[i]); + } + + seat->cursor_left_ptr = wl_cursor_theme_get_cursor(seat->cursor_theme, "left_ptr"); + seat->current_cursor = seat->cursor_left_ptr; + cursor_updated = true; + } + } + + struct wl_cursor *wl_cursor = seat->cursor_left_ptr; + if (ctx.active == COMPONENT_SLOT_SHADOW && + (ctx.frame_capabilities & LIBDECOR_ACTION_RESIZE)){ + enum libdecor_resize_edge edge = component_edge(COMPONENT_SLOT_SHADOW, seat->pointer_x, seat->pointer_y); + if (edge != LIBDECOR_RESIZE_EDGE_NONE){ + wl_cursor = seat->cursors[edge - 1]; + } + } + + if (seat->current_cursor != wl_cursor) { + seat->current_cursor = wl_cursor; + cursor_updated = true; + } + } + } + + return(cursor_updated); +} + static void update_touch_focus(struct seat *seat, wl_fixed_t x, wl_fixed_t y){ - if (GTK_IS_WIDGET(ctx.header) && ctx.touch_active->type == HEADER){ + if (GTK_IS_WIDGET(ctx.header) && ctx.touch_active == COMPONENT_SLOT_HEADER){ struct header_element_data new_focus = get_header_focus(GTK_HEADER_BAR(ctx.header), wl_fixed_to_int(x), wl_fixed_to_int(y)); if (ctx.hdr_focus.widget != new_focus.widget){ ctx.hdr_focus = new_focus; diff --git a/digesting_libdecor.h b/digesting_libdecor.h index 74d9cc9..0e2e90b 100644 --- a/digesting_libdecor.h +++ b/digesting_libdecor.h @@ -59,6 +59,11 @@ typedef struct Extent2D{ int h; } Extent2D; +typedef struct Bounds2D{ + int x[2]; + int y[2]; +} Bounds2D; + // libdecor.h struct libdecor_configuration; @@ -122,13 +127,6 @@ enum libdecor_wm_capabilities { // libdecor-plugin.h -struct libdecor_limits { - int min_width; - int min_height; - int max_width; - int max_height; -}; - enum header_element { HEADER_NONE, HEADER_FULL, /* entire header bar */ @@ -159,22 +157,19 @@ enum decoration_type { DECORATION_TYPE_TITLE_ONLY }; -enum component { - NONE = 0, - SHADOW, - HEADER, +enum component_slot { + COMPONENT_SLOT_NONE, + COMPONENT_SLOT_SHADOW, + COMPONENT_SLOT_HEADER, + COMPONENT_SLOT_COUNT }; struct border_component { - enum component type; + enum component_slot slot; struct wl_surface *wl_surface; struct wl_subsurface *wl_subsurface; struct buffer *buffer; bool opaque; - int scale; - - struct wl_list child_components; /* border_component::link */ - struct wl_list link; /* border_component::child_components */ }; // #include "libdecor.c" @@ -228,7 +223,6 @@ struct seat { struct wl_surface *cursor_surface; struct wl_cursor *current_cursor; - int cursor_scale; struct wl_cursor_theme *cursor_theme; /* cursors for resize edges and corners */ @@ -259,7 +253,6 @@ struct buffer { size_t data_size; int width; int height; - int scale; int buffer_width; int buffer_height; }; @@ -275,14 +268,9 @@ enum titlebar_gesture { void libdecor_frame_set_visibility(bool visible); void libdecor_frame_show_window_menu(struct wl_seat *wl_seat, uint32_t serial, int x, int y); -void libdecor_frame_translate_coordinate(int surface_x, int surface_y, int *frame_x, int *frame_y); - -void libdecor_frame_resize(struct wl_seat *wl_seat, uint32_t serial, enum libdecor_resize_edge edge); -void libdecor_frame_move(struct wl_seat *wl_seat, uint32_t serial); void libdecor_frame_commit(int w, int h, struct libdecor_configuration *configuration); void libdecor_frame_set_fullscreen(struct wl_output *output); void libdecor_frame_unset_fullscreen(void); -void libdecor_frame_map(void); bool libdecor_configuration_get_content_size(struct libdecor_configuration *configuration, int *width, int *height); @@ -313,24 +301,25 @@ static void do_map(void); static const char *libdecor_gtk_proxy_tag = "libdecor-gtk"; static void libdecor_plugin_gtk_frame_free(void); -static void libdecor_plugin_gtk_frame_commit(struct libdecor_state *state, struct libdecor_configuration *configuration); -static void libdecor_plugin_gtk_frame_get_border_size(enum libdecor_window_state window_state, int *left, int *right, int *top, int *bottom); +static void libdecor_plugin_gtk_frame_commit(void); +static Bounds2D border_size_from_window_state(enum libdecor_window_state window_state); static bool update_local_cursor(struct seat *seat); static void draw_decoration(void); static void draw_header_button(cairo_t *cr, cairo_surface_t *surface, enum header_element button_type); -static void redraw_scale(struct border_component *cmpnt); static void buffer_free(struct buffer *buffer); static void draw_border_component(struct border_component *border_component); static bool own_proxy(void *proxy); -static struct border_component * border_component_from_wl_surface(const struct wl_surface *surface); +static enum component_slot component_slot_from_wl_surface(const struct wl_surface *surface); static struct header_element_data get_header_focus(const GtkHeaderBar *header_bar, const int x, const int y); static void draw_title_bar(void); -enum libdecor_resize_edge component_edge(const struct border_component *cmpnt, const int pointer_x, const int pointer_y, const int margin); +enum libdecor_resize_edge component_edge(const enum component_slot slot, const int pointer_x, const int pointer_y); static void toggle_maximized(void); static void update_touch_focus(struct seat *seat, wl_fixed_t x, wl_fixed_t y); +static enum xdg_toplevel_resize_edge xdg_edge_from_edge(enum libdecor_resize_edge edge); + // digesting_libdecor typedef struct Ctx{ @@ -375,7 +364,7 @@ typedef struct Ctx{ //struct libdecor_frame_private; char *title; - struct libdecor_limits content_limits; + Bounds2D size_bounds; struct xdg_toplevel *parent; struct libdecor_configuration *pending_configuration; @@ -391,8 +380,6 @@ typedef struct Ctx{ enum libdecor_capabilities frame_capabilities; enum libdecor_wm_capabilities wm_capabilities; - /* original limits for interactive resize */ - struct libdecor_limits interactive_limits; bool visible; //struct libdecor_frame_gtk; @@ -405,20 +392,17 @@ typedef struct Ctx{ enum libdecor_capabilities gtk_capabilities; - struct border_component *active; - struct border_component *touch_active; - struct border_component *focus; - struct border_component *grab; + enum component_slot active; + enum component_slot touch_active; + enum component_slot focus; + enum component_slot grab; + struct border_component component_slot[COMPONENT_SLOT_COUNT]; bool shadow_showing; - struct border_component shadow; - - GtkWidget *window; /* offscreen window for rendering */ - GtkWidget *header; /* header bar with widgets */ - struct border_component headerbar; + GtkWidget *window; + GtkWidget *header; struct header_element_data hdr_focus; - /* store pre-processed shadow tile */ cairo_surface_t *shadow_blur; struct { @@ -426,9 +410,9 @@ typedef struct Ctx{ int button_pressed_count; uint32_t first_pressed_button; uint32_t first_pressed_time; - double pressed_x; - double pressed_y; - uint32_t pressed_serial; + int pressed_x; + int pressed_y; + uint32_t serial; } titlebar_gesture; } Ctx;