From 7103c61c713eb61ffc24f07f3d9c08ad389a9480 Mon Sep 17 00:00:00 2001 From: Allen Webster Date: Mon, 2 Mar 2026 16:42:00 -0800 Subject: [PATCH] [digesting_libdecor] simplify CSD toggling --- digesting_libdecor.c | 894 ++++++++++++++++++++++--------------------- digesting_libdecor.h | 15 +- 2 files changed, 457 insertions(+), 452 deletions(-) diff --git a/digesting_libdecor.c b/digesting_libdecor.c index 2d9321d..852d50e 100755 --- a/digesting_libdecor.c +++ b/digesting_libdecor.c @@ -288,15 +288,7 @@ 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 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){ - Sides2D 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]; - } - // event to user (inner_w,inner_h) + // TODO(allen): } #endif @@ -342,12 +334,56 @@ xdg_toplevel_decoration_configure(void *data, struct zxdg_toplevel_decoration_v1 } const struct zxdg_toplevel_decoration_v1_listener -xdg_toplevel_decoration_listener = { xdg_toplevel_decoration_configure, }; +xdg_toplevel_decoration_listener = { xdg_toplevel_decoration_configure }; static GtkWidget* find_widget_by_type(GtkWidget *root, enum header_element type); -static void ensure_title_bar_surfaces(void); static void ensure_component(struct border_component *cmpnt); +static void +hide_border_component(struct border_component *border_component){ + if (border_component->wl_surface != 0){ + wl_surface_attach(border_component->wl_surface, 0, 0, 0); + wl_surface_commit(border_component->wl_surface); + } +} + +static void +border_component_reallocate(struct border_component *component, int w, int h){ + if (component->wl_buffer != 0){ + wl_buffer_destroy(component->wl_buffer); + component->wl_buffer = 0; + } + if (component->data != 0){ + munmap(component->data, component->data_size); + component->data = 0; + } + component->data_size = 0; + component->width = 0; + component->height = 0; + + int stride = 4*w; + int size = stride*h; + + int fd = os_create_anonymous_file(size); + if (fd >= 0){ + void *data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (data != MAP_FAILED){ + enum wl_shm_format fmt = WL_SHM_FORMAT_ARGB8888; + struct wl_shm_pool *pool = wl_shm_create_pool(ctx.wl_shm, fd, size); + struct wl_buffer *wl_buffer = wl_shm_pool_create_buffer(pool, 0, w, h, stride, fmt); + wl_shm_pool_destroy(pool); + + component->wl_buffer = wl_buffer; + component->data = data; + component->data_size = size; + component->width = w; + component->height = h; + } + + close(fd); + } +} + int main(){ /* get desktop settings */ ctx.color_scheme = desktop_settings_get_color_scheme(); @@ -367,7 +403,8 @@ int main(){ g_object_set(gtk_settings_get_default(), "gtk-application-prefer-dark-theme", - (ctx.color_scheme == LIBDECOR_COLOR_SCHEME_PREFER_DARK), NULL); + (ctx.color_scheme == LIBDECOR_COLOR_SCHEME_PREFER_DARK), + NULL); if (!gtk_init_success){ printf("failed to initialize gtk\n"); @@ -663,6 +700,7 @@ int main(){ } ctx.seat->current_cursor = cursor; } + if (ctx.seat->current_cursor != 0){ struct wl_cursor_image *image = ctx.seat->current_cursor->images[0]; struct wl_buffer *buffer = wl_cursor_image_get_buffer(image); @@ -673,6 +711,7 @@ int main(){ wl_pointer_set_cursor(ctx.seat->wl_pointer, ctx.seat->serial, ctx.seat->cursor_surface, image->hotspot_x, image->hotspot_y); } +#if 1 if (ctx.pointer_leave){ ctx.pointer_leave = 0; ctx.titlebar_gesture.state = TITLEBAR_GESTURE_STATE_INIT; @@ -851,46 +890,404 @@ int main(){ default: break; } } +#endif /* apply new surface config */ - if (ctx.has_cached_config){ - if (ctx.cached_config.initialized){ - ctx.frame_window_state = ctx.cached_config.window_state; + { + bool csd = 0; + if (ctx.visible && + ctx.decoration_mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE){ + csd = 1; } - if (ctx.cached_config.initialized && - ctx.cached_config.window_width != 0 && - ctx.cached_config.window_height != 0){ - int w = ctx.cached_config.window_width; - int h = ctx.cached_config.window_height; + if (csd && !ctx.csd_active){ + ctx.csd_active = 1; - if (ctx.visible && ctx.decoration_mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE){ - Sides2D border_size = border_size_from_window_state(ctx.cached_config.window_state); - w -= border_size.x[0] + border_size.x[1]; - h -= border_size.y[0] + border_size.y[1]; + ensure_component(&ctx.component_slot[COMPONENT_SLOT_SHADOW]); + ensure_component(&ctx.component_slot[COMPONENT_SLOT_HEADER]); + + { + if (ctx.component_slot[COMPONENT_SLOT_SHADOW].wl_surface != 0){ + 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)){ + gtk_widget_destroy(ctx.header); + ctx.header = 0; + } + if (GTK_IS_WIDGET(ctx.window)){ + gtk_widget_destroy(ctx.window); + ctx.window = 0; + } + + ctx.window = gtk_offscreen_window_new(); + ctx.header = gtk_header_bar_new(); + + g_object_get(gtk_widget_get_settings(ctx.window), + "gtk-double-click-time", &ctx.double_click_time_ms, + NULL); + g_object_set(ctx.header, + "title", ctx.title, + "has-subtitle", FALSE, + "show-close-button", TRUE, + NULL); + + GtkStyleContext *context_hdr = gtk_widget_get_style_context(ctx.header); + gtk_style_context_add_class(context_hdr, GTK_STYLE_CLASS_TITLEBAR); + gtk_style_context_add_class(context_hdr, "default-decoration"); + + gtk_window_set_titlebar(GTK_WINDOW(ctx.window), ctx.header); + gtk_header_bar_set_show_close_button(GTK_HEADER_BAR(ctx.header), TRUE); + + gtk_window_set_resizable(GTK_WINDOW(ctx.window), (ctx.frame_capabilities & LIBDECOR_ACTION_RESIZE) != 0); + } + } + if (!csd && ctx.csd_active){ + if (ctx.header != 0){ + gtk_widget_destroy(ctx.header); + ctx.header = 0; + } + if (ctx.window != 0){ + gtk_widget_destroy(ctx.window); + ctx.window = 0; } - if (!(ctx.cached_config.window_state & LIBDECOR_WINDOW_STATE_NON_FLOATING)){ - if (ctx.size_bounds.x[0] > 0){ - w = MAX(ctx.size_bounds.x[0], w); + for (int i = 1; i < COMPONENT_SLOT_COUNT; i += 1){ + struct border_component * border_component = &ctx.component_slot[i]; + if (border_component->wl_subsurface != 0){ + wl_subsurface_destroy(border_component->wl_subsurface); } - if (ctx.size_bounds.x[1] > 0){ - w = MIN(w, ctx.size_bounds.x[1]); + if (border_component->wl_surface != 0){ + wl_surface_destroy(border_component->wl_surface); } - if (ctx.size_bounds.y[0] > 0){ - h = MAX(ctx.size_bounds.y[0], h); + if (border_component->wl_buffer != 0){ + wl_buffer_destroy(border_component->wl_buffer); } - if (ctx.size_bounds.y[1] > 0){ - h = MIN(h, ctx.size_bounds.y[1]); + if (border_component->data != 0){ + munmap(border_component->data, border_component->data_size); + } + } + memset(ctx.component_slot, 0, sizeof ctx.component_slot); + } + + if (ctx.has_cached_config){ + if (ctx.cached_config.initialized){ + ctx.frame_window_state = ctx.cached_config.window_state; + } + } + + enum decoration_type decoration_type = DECORATION_TYPE_ALL; + if (ctx.frame_window_state & LIBDECOR_WINDOW_STATE_FULLSCREEN){ + decoration_type = DECORATION_TYPE_NONE; + } + else if (ctx.frame_window_state & (LIBDECOR_WINDOW_STATE_MAXIMIZED | + LIBDECOR_WINDOW_STATE_TILED_LEFT | + LIBDECOR_WINDOW_STATE_TILED_RIGHT | + LIBDECOR_WINDOW_STATE_TILED_TOP | + LIBDECOR_WINDOW_STATE_TILED_BOTTOM)){ + decoration_type = DECORATION_TYPE_TITLE_ONLY; + } + + bool shadow = 0; + bool title_bar = 0; + if (csd){ + switch (decoration_type){ + case DECORATION_TYPE_NONE: break; + case DECORATION_TYPE_ALL: { shadow = 1; title_bar = 1; }break; + case DECORATION_TYPE_TITLE_ONLY: { title_bar = 1; }break; + } + + if (shadow){ + //ensure_component(&ctx.component_slot[COMPONENT_SLOT_SHADOW]); + } + else{ + hide_border_component(&ctx.component_slot[COMPONENT_SLOT_SHADOW]); + } + + if (title_bar){ + //ensure_component(&ctx.component_slot[COMPONENT_SLOT_HEADER]); + } + else{ + hide_border_component(&ctx.component_slot[COMPONENT_SLOT_HEADER]); + } + } + + if (csd){ + if (title_bar){ +#if 0 + if (ctx.header == 0){ + if (ctx.component_slot[COMPONENT_SLOT_SHADOW].wl_surface != 0){ + 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)){ + gtk_widget_destroy(ctx.header); + ctx.header = 0; + } + if (GTK_IS_WIDGET(ctx.window)){ + gtk_widget_destroy(ctx.window); + ctx.window = 0; + } + + ctx.window = gtk_offscreen_window_new(); + ctx.header = gtk_header_bar_new(); + + g_object_get(gtk_widget_get_settings(ctx.window), + "gtk-double-click-time", &ctx.double_click_time_ms, + NULL); + g_object_set(ctx.header, + "title", ctx.title, + "has-subtitle", FALSE, + "show-close-button", TRUE, + NULL); + + GtkStyleContext *context_hdr = gtk_widget_get_style_context(ctx.header); + gtk_style_context_add_class(context_hdr, GTK_STYLE_CLASS_TITLEBAR); + gtk_style_context_add_class(context_hdr, "default-decoration"); + + gtk_window_set_titlebar(GTK_WINDOW(ctx.window), ctx.header); + gtk_header_bar_set_show_close_button(GTK_HEADER_BAR(ctx.header), TRUE); + + gtk_window_set_resizable(GTK_WINDOW(ctx.window), (ctx.frame_capabilities & LIBDECOR_ACTION_RESIZE) != 0); + } +#endif + } + } + + Sides2D csd_size = {0}; + if (csd){ + if (title_bar){ + gtk_widget_show_all(ctx.window); + gtk_widget_get_preferred_height(ctx.header, 0, &csd_size.y[0]); + } + } + + if (ctx.has_cached_config){ + if (ctx.cached_config.initialized && + ctx.cached_config.window_width != 0 && + ctx.cached_config.window_height != 0){ + int w = ctx.cached_config.window_width; + int h = ctx.cached_config.window_height; + + if (csd){ + w -= csd_size.x[0] + csd_size.x[1]; + h -= csd_size.y[0] + csd_size.y[1]; + } + + if (!(ctx.cached_config.window_state & LIBDECOR_WINDOW_STATE_NON_FLOATING)){ + w = CLAMP_(ctx.size_bounds.x[0], w, ctx.size_bounds.x[1]); + h = CLAMP_(ctx.size_bounds.y[0], h, ctx.size_bounds.y[1]); + } + + ctx.w = w; + ctx.h = h; + } + } + + if (csd){ + if (title_bar){ + enum libdecor_window_state state = ctx.frame_window_state; + + if (!(state & LIBDECOR_WINDOW_STATE_ACTIVE)){ + gtk_widget_set_state_flags(ctx.window, GTK_STATE_FLAG_BACKDROP, true); + } + else{ + gtk_widget_unset_state_flags(ctx.window, GTK_STATE_FLAG_BACKDROP); + } + GtkStyleContext *style = gtk_widget_get_style_context(ctx.window); + if (!(ctx.frame_window_state & LIBDECOR_WINDOW_STATE_NON_FLOATING)){ + gtk_style_context_remove_class(style, "maximized"); + } + else{ + gtk_style_context_add_class(style, "maximized"); + } + gtk_widget_show_all(ctx.window); + + int preferred_min_width; + { + gtk_header_bar_set_title(GTK_HEADER_BAR(ctx.header), ""); + gtk_widget_get_preferred_width(ctx.header, NULL, &preferred_min_width); + gtk_header_bar_set_title(GTK_HEADER_BAR(ctx.header), ctx.title); + } + + ctx.size_bounds.x[0] = CLAMP_BOT(ctx.size_bounds.x[0], preferred_min_width); + ctx.size_bounds.x[1] = CLAMP_BOT(ctx.size_bounds.x[1], ctx.size_bounds.x[0]); + } + } + + if (!(ctx.frame_capabilities & LIBDECOR_ACTION_RESIZE)){ + xdg_toplevel_set_min_size(ctx.xdg_toplevel, ctx.w, ctx.h); + xdg_toplevel_set_max_size(ctx.xdg_toplevel, ctx.w, ctx.h); + } + + else{ + int csd_added_w = csd_size.x[0] + csd_size.x[1]; + int csd_added_h = csd_size.y[0] + csd_size.y[1]; + for (int i = 0; i < 2; i += 1){ + int mw = ctx.size_bounds.x[i] + csd_added_w; + int mh = ctx.size_bounds.y[i] + csd_added_h; + if (i == 0){ + xdg_toplevel_set_min_size(ctx.xdg_toplevel, mw, mh); + } + else{ + xdg_toplevel_set_max_size(ctx.xdg_toplevel, mw, mh); + } + } + } + + if (csd){ + if (shadow){ + Extent2D extent = {0}; + { + extent.x = -(int)SHADOW_MARGIN; + extent.y = -(int)(SHADOW_MARGIN + csd_size.y[0]); + extent.w = ctx.w + 2*SHADOW_MARGIN; + extent.h = csd_size.y[0] + ctx.h + 2*SHADOW_MARGIN; + } + + struct wl_region *input_region = wl_compositor_create_region(ctx.wl_compositor); + wl_region_add(input_region, 0, 0, extent.w, extent.h); + wl_region_subtract(input_region, -extent.x, -extent.y, ctx.w, ctx.h); + wl_surface_set_input_region(ctx.component_slot[COMPONENT_SLOT_SHADOW].wl_surface, input_region); + wl_region_destroy(input_region); + + { + enum component_slot slot = COMPONENT_SLOT_SHADOW; + struct border_component *component = &ctx.component_slot[slot]; + border_component_reallocate(component, extent.w, extent.h); + + memset(component->data, 0, component->data_size); + { + int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, component->width); + cairo_surface_t *surface = cairo_image_surface_create_for_data(component->data, CAIRO_FORMAT_ARGB32, component->width, component->height, stride); + cairo_t *cr = cairo_create(surface); + cairo_surface_set_device_scale(surface, 1, 1); + + render_shadow(cr, ctx.shadow_blur, + -(int)SHADOW_MARGIN/2, -(int)SHADOW_MARGIN/2, + component->width + SHADOW_MARGIN, component->height + SHADOW_MARGIN, + 64, 64); + cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR); + cairo_rectangle(cr, -extent.x, -extent.y, ctx.w, ctx.h); + cairo_fill(cr); + + cairo_destroy(cr); + cairo_surface_destroy(surface); + } + + wl_surface_attach(component->wl_surface, component->wl_buffer, 0, 0); + wl_surface_set_buffer_scale(component->wl_surface, 1); + wl_surface_commit(component->wl_surface); + wl_surface_damage_buffer(component->wl_surface, 0, 0, extent.w, extent.h); + wl_subsurface_set_position(component->wl_subsurface, extent.x, extent.y); } } - ctx.w = w; - ctx.h = h; + if (title_bar){ + Extent2D extent = {0}; + { + extent.x = 0; + extent.y = -csd_size.y[0]; + extent.w = ctx.w; + extent.h = csd_size.y[0]; + } + + { + GtkAllocation allocation = {0, 0, ctx.w, csd_size.y[0]}; + gtk_widget_size_allocate(ctx.header, &allocation); + } + + { + enum component_slot slot = COMPONENT_SLOT_HEADER; + struct border_component *component = &ctx.component_slot[slot]; + border_component_reallocate(component, extent.w, extent.h); + + memset(component->data, 0, component->data_size); + { + int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, component->width); + cairo_surface_t *surface = cairo_image_surface_create_for_data(component->data, CAIRO_FORMAT_ARGB32, component->width, component->height, stride); + cairo_t *cr = cairo_create(surface); + cairo_surface_set_device_scale(surface, 1, 1); + + { + /* background */ + { + GtkAllocation allocation; + gtk_widget_get_allocation(GTK_WIDGET(ctx.header), &allocation); + GtkStyleContext* style = gtk_widget_get_style_context(ctx.header); + gtk_render_background(style, cr, allocation.x, allocation.y, allocation.width, allocation.height); + } + + /* title */ + { + GtkWidget *label = find_widget_by_type(ctx.header, HEADER_TITLE); + + GtkAllocation allocation; + gtk_widget_get_allocation(label, &allocation); + + cairo_surface_t *label_surface = cairo_surface_create_for_rectangle(surface, allocation.x, allocation.y, allocation.width, allocation.height); + + cairo_t *cr2 = cairo_create(label_surface); + gtk_widget_size_allocate(label, &allocation); + gtk_widget_draw(label, cr2); + cairo_destroy(cr2); + cairo_surface_destroy(label_surface); + } + + /* buttons */ + { + enum header_element buttons[3] = {0}; + size_t nbuttons = 0; + + if ((ctx.frame_capabilities & LIBDECOR_ACTION_MINIMIZE)){ + buttons[nbuttons] = HEADER_MIN; + nbuttons += 1; + } + if ((ctx.frame_capabilities & LIBDECOR_ACTION_RESIZE)){ + buttons[nbuttons] = HEADER_MAX; + nbuttons += 1; + } + if ((ctx.frame_capabilities & LIBDECOR_ACTION_CLOSE)){ + buttons[nbuttons] = HEADER_CLOSE; + nbuttons += 1; + } + + for (int i = 0; i < nbuttons; i += 1){ + enum header_element button_type = buttons[i]; + draw_header_button(cr, surface, button_type); + } + } + } + + cairo_destroy(cr); + cairo_surface_destroy(surface); + } + + wl_surface_attach(component->wl_surface, component->wl_buffer, 0, 0); + wl_surface_set_buffer_scale(component->wl_surface, 1); + wl_surface_commit(component->wl_surface); + wl_surface_damage_buffer(component->wl_surface, 0, 0, extent.w, extent.h); + wl_subsurface_set_position(component->wl_subsurface, extent.x, extent.y); + } + } + } + + { + Extent2D extent = {0}; + extent.w = ctx.w; + extent.h = ctx.h; + if (csd){ + extent.x = -csd_size.x[0]; + extent.y = -csd_size.y[0]; + extent.w += csd_size.x[0] + csd_size.x[1]; + extent.h += csd_size.y[0] + csd_size.y[1]; + } + xdg_surface_set_window_geometry(ctx.xdg_surface, extent.x, extent.y, extent.w, extent.h); } } - frame_commit(); wl_surface_commit(ctx.wl_surface); if (ctx.has_cached_config){ @@ -955,175 +1352,31 @@ int main(){ //#include "libdecor.c" -static enum decoration_type -decoration_type_from_window_state(enum libdecor_window_state window_state){ - enum decoration_type result = DECORATION_TYPE_ALL; - if (window_state & LIBDECOR_WINDOW_STATE_FULLSCREEN){ - result = DECORATION_TYPE_NONE; - } - else if (window_state & (LIBDECOR_WINDOW_STATE_MAXIMIZED | - LIBDECOR_WINDOW_STATE_TILED_LEFT | - LIBDECOR_WINDOW_STATE_TILED_RIGHT | - LIBDECOR_WINDOW_STATE_TILED_TOP | - LIBDECOR_WINDOW_STATE_TILED_BOTTOM)){ - result = DECORATION_TYPE_TITLE_ONLY; +static Extent2D +extent2d_from_component_slot(enum component_slot slot, int title_height){ + Extent2D result = {0}; + + switch (slot){ + default: case COMPONENT_SLOT_NONE: break; + + case COMPONENT_SLOT_SHADOW: { + result.x = -(int)SHADOW_MARGIN; + result.y = -(int)(SHADOW_MARGIN + title_height); + result.w = ctx.w + 2*SHADOW_MARGIN; + result.h = title_height + ctx.h + 2*SHADOW_MARGIN; + }break; + + case COMPONENT_SLOT_HEADER: { + result.x = 0; + result.y = -title_height; + result.w = ctx.w; + result.h = title_height; + }break; } + return(result); } -static void -hide_border_component(struct border_component *border_component){ - if (border_component->wl_surface){ - wl_surface_attach(border_component->wl_surface, 0, 0, 0); - wl_surface_commit(border_component->wl_surface); - } -} - -void -frame_commit(void){ - bool csd = false; - if (ctx.visible && - ctx.decoration_mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE){ - csd = true; - } - - Sides2D border_size = {0}; - if (csd){ - border_size = border_size_from_window_state(ctx.frame_window_state); - } - - if (!(ctx.frame_capabilities & LIBDECOR_ACTION_RESIZE)){ - xdg_toplevel_set_min_size(ctx.xdg_toplevel, ctx.w, ctx.h); - xdg_toplevel_set_max_size(ctx.xdg_toplevel, ctx.w, ctx.h); - } - - else{ - int csd_added_w = border_size.x[0] + border_size.x[1]; - int csd_added_h = border_size.y[0] + border_size.y[1]; - for (int i = 0; i < 2; i += 1){ - int mw = 0; - int mh = 0; - if (ctx.size_bounds.x[i] > 0 && ctx.size_bounds.y[i] > 0){ - mw = ctx.size_bounds.x[i] + csd_added_w; - mh = ctx.size_bounds.y[i] + csd_added_h; - } - if (i == 0){ - xdg_toplevel_set_min_size(ctx.xdg_toplevel, mw, mh); - } - else{ - xdg_toplevel_set_max_size(ctx.xdg_toplevel, mw, mh); - } - } - } - - if (csd){ - ctx.decoration_type = decoration_type_from_window_state(ctx.frame_window_state); - - bool shadow = 0; - bool title_bar = 0; - switch (ctx.decoration_type){ - case DECORATION_TYPE_NONE: break; - case DECORATION_TYPE_ALL: { shadow = 1; title_bar = 1; }break; - case DECORATION_TYPE_TITLE_ONLY: { title_bar = 1; }break; - } - - if (shadow){ - ctx.component_slot[COMPONENT_SLOT_SHADOW].opaque = false; - ensure_component(&ctx.component_slot[COMPONENT_SLOT_SHADOW]); - draw_border_component(COMPONENT_SLOT_SHADOW); - ctx.shadow_showing = true; - } - else{ - hide_border_component(&ctx.component_slot[COMPONENT_SLOT_SHADOW]); - ctx.shadow_showing = false; - } - - if (title_bar){ - ensure_title_bar_surfaces(); - - enum libdecor_window_state state = ctx.frame_window_state; - - if (!(state & LIBDECOR_WINDOW_STATE_ACTIVE)){ - gtk_widget_set_state_flags(ctx.window, GTK_STATE_FLAG_BACKDROP, true); - } - else{ - gtk_widget_unset_state_flags(ctx.window, GTK_STATE_FLAG_BACKDROP); - } - GtkStyleContext *style = gtk_widget_get_style_context(ctx.window); - if (!(ctx.frame_window_state & LIBDECOR_WINDOW_STATE_NON_FLOATING)){ - gtk_style_context_remove_class(style, "maximized"); - } - else{ - gtk_style_context_add_class(style, "maximized"); - } - gtk_widget_show_all(ctx.window); - - int pref_width; - { - 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); - } - - ctx.size_bounds.x[0] = CLAMP_BOT(ctx.size_bounds.x[0], pref_width); - if (ctx.size_bounds.x[1] != 0){ - ctx.size_bounds.x[1] = CLAMP_BOT(ctx.size_bounds.x[1], ctx.size_bounds.x[0]); - } - - if (ctx.w < ctx.size_bounds.x[0]){ - ctx.w = ctx.size_bounds.x[0]; - frame_commit(); - } - else{ - GtkAllocation allocation = {0, 0, ctx.w, 0}; - gtk_widget_get_preferred_height(ctx.header, 0, &allocation.height); - gtk_widget_size_allocate(ctx.header, &allocation); - draw_border_component(COMPONENT_SLOT_HEADER); - } - } - else{ - hide_border_component(&ctx.component_slot[COMPONENT_SLOT_HEADER]); - } - } - else{ - ctx.decoration_type = DECORATION_TYPE_NONE; - - g_clear_pointer(&ctx.header, gtk_widget_destroy); - g_clear_pointer(&ctx.window, gtk_widget_destroy); - - for (int i = 1; i < COMPONENT_SLOT_COUNT; i += 1){ - struct border_component * border_component = &ctx.component_slot[i]; - if (border_component->wl_subsurface != 0){ - wl_subsurface_destroy(border_component->wl_subsurface); - } - if (border_component->wl_surface != 0){ - wl_surface_destroy(border_component->wl_surface); - } - if (border_component->wl_buffer != 0){ - wl_buffer_destroy(border_component->wl_buffer); - } - if (border_component->data != 0){ - munmap(border_component->data, border_component->data_size); - } - } - memset(ctx.component_slot, 0, sizeof ctx.component_slot); - ctx.shadow_showing = false; - } - - { - Extent2D extent = {0}; - extent.w = ctx.w; - extent.h = ctx.h; - if (csd){ - extent.x = -border_size.x[0]; - extent.y = -border_size.y[0]; - extent.w += border_size.x[0] + border_size.x[1]; - extent.h += border_size.y[0] + border_size.y[1]; - } - xdg_surface_set_window_geometry(ctx.xdg_surface, extent.x, extent.y, extent.w, extent.h); - } -} - //#include "libdecor-cairo-blur.c" int blur_surface(cairo_surface_t *surface, int margin){ @@ -1533,77 +1786,6 @@ ensure_component(struct border_component *cmpnt){ } } -static void -ensure_title_bar_surfaces(void){ - ctx.component_slot[COMPONENT_SLOT_HEADER].opaque = false; - ensure_component(&ctx.component_slot[COMPONENT_SLOT_HEADER]); - - 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)){ - gtk_widget_destroy(ctx.header); - ctx.header = 0; - } - if (GTK_IS_WIDGET(ctx.window)){ - gtk_widget_destroy(ctx.window); - ctx.window = 0; - } - - ctx.window = gtk_offscreen_window_new(); - ctx.header = gtk_header_bar_new(); - - g_object_get(gtk_widget_get_settings(ctx.window), - "gtk-double-click-time", &ctx.double_click_time_ms, - NULL); - g_object_set(ctx.header, - "title", ctx.title, - "has-subtitle", FALSE, - "show-close-button", TRUE, - NULL); - - GtkStyleContext *context_hdr = gtk_widget_get_style_context(ctx.header); - gtk_style_context_add_class(context_hdr, GTK_STYLE_CLASS_TITLEBAR); - gtk_style_context_add_class(context_hdr, "default-decoration"); - - gtk_window_set_titlebar(GTK_WINDOW(ctx.window), ctx.header); - gtk_header_bar_set_show_close_button(GTK_HEADER_BAR(ctx.header), TRUE); - - gtk_window_set_resizable(GTK_WINDOW(ctx.window), (ctx.frame_capabilities & LIBDECOR_ACTION_RESIZE) != 0); -} - -static Extent2D -extent2d_from_component_slot(enum component_slot slot){ - Extent2D result = {0}; - int title_height = 0; - - if (GTK_IS_WIDGET(ctx.header)){ - title_height = gtk_widget_get_allocated_height(ctx.header); - } - - switch (slot){ - default: case COMPONENT_SLOT_NONE: break; - - case COMPONENT_SLOT_SHADOW: { - result.x = -(int)SHADOW_MARGIN; - result.y = -(int)(SHADOW_MARGIN + title_height); - result.w = ctx.w + 2*SHADOW_MARGIN; - result.h = title_height + ctx.h + 2*SHADOW_MARGIN; - }break; - - case COMPONENT_SLOT_HEADER: { - result.x = 0; - result.y = -title_height; - result.w = gtk_widget_get_allocated_width(ctx.header); - result.h = title_height; - }break; - } - - return(result); -} - static void draw_header_button(cairo_t *cr, cairo_surface_t *surface, enum header_element button_type){ @@ -1738,174 +1920,6 @@ draw_header_button(cairo_t *cr, cairo_surface_t *surface, } } -static void -draw_border_component(enum component_slot slot){ - if (slot < COMPONENT_SLOT_COUNT && - ctx.component_slot[slot].wl_surface != 0){ - struct border_component *component = &ctx.component_slot[slot]; - - if (slot == COMPONENT_SLOT_SHADOW && ctx.shadow_showing){ - struct wl_region *input_region; - Extent2D extent = extent2d_from_component_slot(COMPONENT_SLOT_SHADOW); - input_region = wl_compositor_create_region(ctx.wl_compositor); - wl_region_add(input_region, 0, 0, extent.w, extent.h); - wl_region_subtract(input_region, -extent.x, -extent.y, ctx.w, ctx.h); - wl_surface_set_input_region(component->wl_surface, input_region); - wl_region_destroy(input_region); - } - - { - if (component->wl_buffer != 0){ - wl_buffer_destroy(component->wl_buffer); - component->wl_buffer = 0; - } - if (component->data != 0){ - munmap(component->data, component->data_size); - component->data = 0; - } - component->data_size = 0; - component->width = 0; - component->height = 0; - } - - Extent2D extent = extent2d_from_component_slot(slot); - { - int width = extent.w; - int height = extent.h; - int stride = 4*width; - int size = stride*height; - - int fd = os_create_anonymous_file(size); - if (fd >= 0){ - void *data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - if (data != MAP_FAILED){ - enum wl_shm_format fmt = (ctx.component_slot[slot].opaque ? - WL_SHM_FORMAT_XRGB8888 : - WL_SHM_FORMAT_ARGB8888); - - struct wl_shm_pool *pool = wl_shm_create_pool(ctx.wl_shm, fd, size); - struct wl_buffer *wl_buffer = wl_shm_pool_create_buffer(pool, 0, width, height, stride, fmt); - wl_shm_pool_destroy(pool); - - component->wl_buffer = wl_buffer; - component->data = data; - component->data_size = size; - component->width = width; - component->height = height; - } - - close(fd); - } - } - - memset(component->data, 0, component->data_size); - { - int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, component->width); - cairo_surface_t *surface = cairo_image_surface_create_for_data(component->data, CAIRO_FORMAT_ARGB32, component->width, component->height, stride); - cairo_t *cr = cairo_create(surface); - cairo_surface_set_device_scale(surface, 1, 1); - - switch (slot){ - default:break; - - case COMPONENT_SLOT_SHADOW: { - render_shadow(cr, ctx.shadow_blur, - -(int)SHADOW_MARGIN/2, -(int)SHADOW_MARGIN/2, - component->width + SHADOW_MARGIN, component->height + SHADOW_MARGIN, - 64, 64); - cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR); - cairo_rectangle(cr, -extent.x, -extent.y, ctx.w, ctx.h); - cairo_fill(cr); - }break; - - case COMPONENT_SLOT_HEADER: { - /* background */ - { - GtkAllocation allocation; - gtk_widget_get_allocation(GTK_WIDGET(ctx.header), &allocation); - GtkStyleContext* style = gtk_widget_get_style_context(ctx.header); - gtk_render_background(style, cr, allocation.x, allocation.y, allocation.width, allocation.height); - } - - /* title */ - { - GtkWidget *label = find_widget_by_type(ctx.header, HEADER_TITLE); - - GtkAllocation allocation; - gtk_widget_get_allocation(label, &allocation); - - cairo_surface_t *label_surface = cairo_surface_create_for_rectangle(surface, allocation.x, allocation.y, allocation.width, allocation.height); - - cairo_t *cr2 = cairo_create(label_surface); - gtk_widget_size_allocate(label, &allocation); - gtk_widget_draw(label, cr2); - cairo_destroy(cr2); - cairo_surface_destroy(label_surface); - } - - /* buttons */ - { - enum header_element buttons[3] = {0}; - size_t nbuttons = 0; - - if ((ctx.frame_capabilities & LIBDECOR_ACTION_MINIMIZE)){ - buttons[nbuttons] = HEADER_MIN; - nbuttons += 1; - } - if ((ctx.frame_capabilities & LIBDECOR_ACTION_RESIZE)){ - buttons[nbuttons] = HEADER_MAX; - nbuttons += 1; - } - if ((ctx.frame_capabilities & LIBDECOR_ACTION_CLOSE)){ - buttons[nbuttons] = HEADER_CLOSE; - nbuttons += 1; - } - - for (int i = 0; i < nbuttons; i += 1){ - enum header_element button_type = buttons[i]; - draw_header_button(cr, surface, button_type); - } - } - }break; - } - - cairo_destroy(cr); - cairo_surface_destroy(surface); - } - - struct wl_surface *component_surface = ctx.component_slot[slot].wl_surface; - struct wl_subsurface *component_subsurface = ctx.component_slot[slot].wl_subsurface; - - wl_surface_attach(component_surface, component->wl_buffer, 0, 0); - wl_surface_set_buffer_scale(component_surface, 1); - wl_surface_commit(component_surface); - wl_surface_damage_buffer(component_surface, 0, 0, extent.w, extent.h); - wl_subsurface_set_position(component_subsurface, extent.x, extent.y); - } -} - -static Sides2D -border_size_from_window_state(enum libdecor_window_state window_state){ - Sides2D 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].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 edge_from_pos(int x, int y){ static const enum libdecor_resize_edge box[9] = { diff --git a/digesting_libdecor.h b/digesting_libdecor.h index b86b378..8bdb385 100644 --- a/digesting_libdecor.h +++ b/digesting_libdecor.h @@ -47,6 +47,7 @@ #define CLAMP_BOT(a, b) MAX(a, b) #define CLAMP_TOP(a, b) MIN(a, b) +#define CLAMP_(a, x, b) CLAMP_BOT(a, CLAMP_TOP(x, b)) #define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0]) @@ -167,7 +168,6 @@ enum component_slot { struct border_component { struct wl_surface *wl_surface; struct wl_subsurface *wl_subsurface; - bool opaque; struct wl_buffer *wl_buffer; void *data; @@ -240,10 +240,6 @@ struct seat{ struct wl_list link; }; - -// libdecor.h -void frame_commit(void); - // #include "libdecor-cairo-blur.h" int blur_surface(cairo_surface_t *surface, int margin); void render_shadow(cairo_t *cr, cairo_surface_t *surface, @@ -267,11 +263,8 @@ static void do_map(void); static const char *libdecor_gtk_proxy_tag = "libdecor-gtk"; -static Sides2D border_size_from_window_state(enum libdecor_window_state window_state); - static struct wl_cursor* wl_cursor_from_pos(int x, int y); static void draw_header_button(cairo_t *cr, cairo_surface_t *surface, enum header_element button_type); -static void draw_border_component(enum component_slot slot); static bool own_proxy(void *proxy); static enum component_slot component_slot_from_wl_surface(const struct wl_surface *surface); @@ -354,14 +347,12 @@ typedef struct Ctx{ bool visible; //struct libdecor_frame_gtk; - enum decoration_type decoration_type; - enum component_slot active; enum component_slot focus; enum component_slot grab; - struct border_component component_slot[COMPONENT_SLOT_COUNT]; - bool shadow_showing; + bool csd_active; + struct border_component component_slot[COMPONENT_SLOT_COUNT]; GtkWidget *window; GtkWidget *header; struct header_element_data hdr_focus;