[digesting_libdecor] split state field out of hdr element, delete dead code, eliminate reducible functions

main
Allen Webster 2026-02-28 21:23:41 -08:00
parent 6e0c97bfcd
commit bea30ea7de
2 changed files with 168 additions and 233 deletions

View File

@ -160,18 +160,18 @@ pointer_motion(void *data, struct wl_pointer *wl_pointer, uint32_t time,
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 != COMPONENT_SLOT_HEADER){
ctx.hdr_focus.type = HEADER_NONE;
}
new_focus = get_header_focus(GTK_HEADER_BAR(ctx.header), seat->pointer_x, seat->pointer_y);
/* only update if widget change so that we keep the state */
if (ctx.hdr_focus.widget != new_focus.widget){
ctx.hdr_focus = new_focus;
ctx.hdr_state = 0;
}
ctx.hdr_focus.state |= GTK_STATE_FLAG_PRELIGHT;
ctx.hdr_state |= GTK_STATE_FLAG_PRELIGHT;
/* redraw with updated button visuals */
draw_title_bar();
wl_surface_commit(ctx.wl_surface);
@ -236,7 +236,7 @@ pointer_button(void *data, struct wl_pointer *wl_pointer, uint32_t serial,
case HEADER_MIN:
case HEADER_MAX:
case HEADER_CLOSE: {
ctx.hdr_focus.state |= GTK_STATE_FLAG_ACTIVE;
ctx.hdr_state |= GTK_STATE_FLAG_ACTIVE;
draw_title_bar();
wl_surface_commit(ctx.wl_surface);
}break;
@ -281,7 +281,7 @@ pointer_button(void *data, struct wl_pointer *wl_pointer, uint32_t serial,
default: break;
}
ctx.hdr_focus.state &= ~GTK_STATE_FLAG_ACTIVE;
ctx.hdr_state &= ~GTK_STATE_FLAG_ACTIVE;
if (GTK_IS_WIDGET(ctx.header)){
draw_title_bar();
wl_surface_commit(ctx.wl_surface);
@ -289,7 +289,7 @@ pointer_button(void *data, struct wl_pointer *wl_pointer, uint32_t serial,
}
}
else{
ctx.hdr_focus.state &= ~GTK_STATE_FLAG_ACTIVE;
ctx.hdr_state &= ~GTK_STATE_FLAG_ACTIVE;
if (GTK_IS_WIDGET(ctx.header)) {
draw_title_bar();
wl_surface_commit(ctx.wl_surface);
@ -364,7 +364,7 @@ touch_down(void *data, struct wl_touch *wl_touch, uint32_t serial,
case HEADER_MIN:
case HEADER_MAX:
case HEADER_CLOSE: {
ctx.hdr_focus.state |= GTK_STATE_FLAG_ACTIVE;
ctx.hdr_state |= GTK_STATE_FLAG_ACTIVE;
draw_title_bar();
wl_surface_commit(ctx.wl_surface);
}break;
@ -422,13 +422,13 @@ touch_up(void *data, struct wl_touch *wl_touch, uint32_t serial, uint32_t time,
}
/* unset active/clicked state once released */
ctx.hdr_focus.state &= ~GTK_STATE_FLAG_ACTIVE;
ctx.hdr_state &= ~GTK_STATE_FLAG_ACTIVE;
if (GTK_IS_WIDGET(ctx.header)) {
draw_title_bar();
wl_surface_commit(ctx.wl_surface);
}
}
else{
seat->touch_focus = 0;
ctx.touch_active = 0;
ctx.hdr_focus.widget = 0;
@ -438,6 +438,7 @@ touch_up(void *data, struct wl_touch *wl_touch, uint32_t serial, uint32_t time,
}
}
}
}
static void
touch_motion(void *data, struct wl_touch *wl_touch, uint32_t time,
@ -716,7 +717,8 @@ const struct xdg_toplevel_listener xdg_toplevel_listener = {
};
static void
xdg_toplevel_decoration_configure(void *data, struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1, uint32_t mode){
xdg_toplevel_decoration_configure(void *data, struct zxdg_toplevel_decoration_v1 *toplevel,
uint32_t mode){
if (!ctx.has_decoration_mode){
ctx.has_decoration_mode = true;
ctx.decoration_mode = mode;
@ -954,7 +956,6 @@ int main(){
xdg_toplevel_set_title(ctx.xdg_toplevel, "Example Window");
ctx.title = strdup("Example Window");
draw_decoration();
wl_surface_commit(ctx.wl_surface);
/* (nodocs-wl_egl) */
@ -1011,16 +1012,11 @@ int main(){
}
}
/* (egl) eglMakeCurrent */
EGLBoolean make_current_success2 = 0;
if (ctx.egl_surface != EGL_NO_SURFACE){
make_current_success2 = eglMakeCurrent(ctx.egl_display, ctx.egl_surface, ctx.egl_surface, ctx.egl_context);
}
/* (egl) eglSwapInterval
** " specifies the minimum number of video frame periods per buffer swap
** for the window associated with the current context "
*/
EGLBoolean swap_interval_success = 0;
if (make_current_success2){
swap_interval_success = eglSwapInterval(ctx.egl_display, 1);
@ -1073,10 +1069,7 @@ int main(){
}
}
if (ctx.close_signal){
exit_loop = 1;
}
/* apply new surface config */
if (ctx.has_cached_config){
ctx.has_cached_config = 0;
if (ctx.cached_config.initialized){
@ -1099,6 +1092,10 @@ int main(){
glClear(GL_COLOR_BUFFER_BIT);
}
if (ctx.close_signal){
exit_loop = 1;
}
/* (egl) eglSwapBuffers
** " back-buffered window surface, then the color buffer is copied
** (posted) to the native window associated with that surface "
@ -1169,28 +1166,6 @@ decoration_type_from_window_state(enum libdecor_window_state window_state){
return(result);
}
static void
free_border_component(struct border_component *border_component){
if (border_component->wl_surface) {
wl_subsurface_destroy(border_component->wl_subsurface);
border_component->wl_subsurface = NULL;
wl_surface_destroy(border_component->wl_surface);
border_component->wl_surface = NULL;
}
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);
}
border_component->wl_buffer = 0;
border_component->data = 0;
border_component->data_size = 0;
border_component->width = 0;
border_component->height = 0;
}
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;
@ -1208,26 +1183,19 @@ xdg_edge_from_edge(enum libdecor_resize_edge edge){
return(result);
}
void
libdecor_frame_set_fullscreen(struct wl_output *output){
xdg_toplevel_set_fullscreen(ctx.xdg_toplevel, output);
}
void
libdecor_frame_unset_fullscreen(void){
xdg_toplevel_unset_fullscreen(ctx.xdg_toplevel);
}
void
libdecor_frame_commit(void){
Sides2D border_size = border_size_from_window_state(ctx.frame_window_state);
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)){
int mw = ctx.frame_content_width;
int mh = ctx.frame_content_height;
@ -1270,8 +1238,28 @@ libdecor_frame_commit(void){
g_clear_pointer(&ctx.header, gtk_widget_destroy);
g_clear_pointer(&ctx.window, gtk_widget_destroy);
free_border_component(&ctx.component_slot[COMPONENT_SLOT_HEADER]);
free_border_component(&ctx.component_slot[COMPONENT_SLOT_SHADOW]);
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);
border_component->wl_subsurface = 0;
}
if (border_component->wl_surface != 0){
wl_surface_destroy(border_component->wl_surface);
border_component->wl_surface = 0;
}
if (border_component->wl_buffer != 0){
wl_buffer_destroy(border_component->wl_buffer);
border_component->wl_buffer = 0;
}
if (border_component->data != 0){
munmap(border_component->data, border_component->data_size);
border_component->data = 0;
}
border_component->data_size = 0;
border_component->width = 0;
border_component->height = 0;
}
ctx.shadow_showing = false;
g_clear_pointer(&ctx.title, free);
@ -1283,7 +1271,6 @@ libdecor_frame_commit(void){
Extent2D extent = {0};
extent.w = ctx.frame_content_width;
extent.h = ctx.frame_content_height;
if (csd){
extent.x = -border_size.x[0];
extent.y = -border_size.y[0];
@ -1546,200 +1533,161 @@ render_shadow(cairo_t *cr, cairo_surface_t *surface,
//#include "os-compatibility.c"
#ifndef HAVE_MKOSTEMP
static int
set_cloexec_or_close(int fd)
{
set_cloexec_or_close(int fd){
bool error = 0;
long flags;
if (fd == -1)
return -1;
if (fd >= 0){
if (fcntl(fd, F_GETFD) == -1){
error = 1;
}
else if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1){
error = 1;
}
flags = fcntl(fd, F_GETFD);
if (flags == -1)
goto err;
if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1)
goto err;
if (error){
close(fd);
fd = -1;
}
}
return fd;
err:
close(fd);
return -1;
}
#endif
static int
create_tmpfile_cloexec(char *tmpname)
{
create_tmpfile_cloexec(char *tmpname){
int fd;
#ifdef HAVE_MKOSTEMP
fd = mkostemp(tmpname, O_CLOEXEC);
if (fd >= 0)
if (fd >= 0){
unlink(tmpname);
}
#else
fd = mkstemp(tmpname);
if (fd >= 0) {
fd = set_cloexec_or_close(fd);
if (fd >= 0) {
unlink(tmpname);
}
#endif
return fd;
return(fd);
}
static int
os_resize_anonymous_file(int fd, off_t size)
{
os_resize_anonymous_file(int fd, off_t size){
#ifdef HAVE_POSIX_FALLOCATE
sigset_t mask;
sigset_t old_mask;
/* posix_fallocate() might be interrupted, so we need to check
* for EINTR and retry in that case.
* However, in the presence of an alarm, the interrupt may trigger
* repeatedly and prevent a large posix_fallocate() to ever complete
* successfully, so we need to first block SIGALRM to prevent
* this.
*/
sigemptyset(&mask);
sigaddset(&mask, SIGALRM);
sigprocmask(SIG_BLOCK, &mask, &old_mask);
/*
* Filesystems that do not support fallocate will return EINVAL or
* EOPNOTSUPP. In this case we need to fall back to ftruncate
*/
do {
errno = posix_fallocate(fd, 0, size);
} while (errno == EINTR);
sigprocmask(SIG_SETMASK, &old_mask, NULL);
if (errno == 0)
return 0;
else if (errno != EINVAL && errno != EOPNOTSUPP)
return -1;
#endif
if (ftruncate(fd, size) < 0)
return -1;
return 0;
int result = 0;
if (errno != 0){
result = -1;
if (errno == EINVAL || errno == EOPNOTSUPP){
if (ftruncate(fd, size) >= 0){
result = 0;
}
}
}
return(result);
/*
* Create a new, unique, anonymous file of the given size, and
* return the file descriptor for it. The file descriptor is set
* CLOEXEC. The file is immediately suitable for mmap()'ing
* the given size at offset zero.
*
* The file should not have a permanent backing store like a disk,
* but may have if XDG_RUNTIME_DIR is not properly implemented in OS.
*
* The file name is deleted from the file system.
*
* The file is suitable for buffer sharing between processes by
* transmitting the file descriptor over Unix sockets using the
* SCM_RIGHTS methods.
*
* If the C library implements posix_fallocate(), it is used to
* guarantee that disk space is available for the file at the
* given size. If disk space is insufficient, errno is set to ENOSPC.
* If posix_fallocate() is not supported, program may receive
* SIGBUS on accessing mmap()'ed file contents instead.
*
* If the C library implements memfd_create(), it is used to create the
* file purely in memory, without any backing file name on the file
* system, and then sealing off the possibility of shrinking it. This
* can then be checked before accessing mmap()'ed file contents, to
* make sure SIGBUS can't happen. It also avoids requiring
* XDG_RUNTIME_DIR.
*/
#else
int result = -1;
if (ftruncate(fd, size) >= 0){
result = 0;
}
return(result);
#endif
}
int
libdecor_os_create_anonymous_file(off_t size){
static const char template[] = "/libdecor-shared-XXXXXX";
const char *path;
char *name;
int fd;
static const char key[] = "/libdecor-shared-XXXXXX";
int fd = -1;
#ifdef HAVE_MEMFD_CREATE
fd = memfd_create("libdecor", MFD_CLOEXEC | MFD_ALLOW_SEALING);
if (fd >= 0){
/* We can add this seal before calling posix_fallocate(), as
* the file is currently zero-sized anyway.
*
* There is also no need to check for the return value, we
* couldn't do anything with it anyway.
*/
fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_SEAL);
} else
}
#endif
{
path = getenv("XDG_RUNTIME_DIR");
if (!path) {
if (fd < 0){
const char *path = getenv("XDG_RUNTIME_DIR");
if (path == 0){
errno = ENOENT;
return -1;
}
name = malloc(strlen(path) + sizeof(template));
if (!name)
return -1;
else{
char *name = malloc(strlen(path) + sizeof(key));
if (name != 0){
strcpy(name, path);
strcat(name, template);
strcat(name, key);
fd = create_tmpfile_cloexec(name);
free(name);
if (fd < 0)
return -1;
}
}
}
if (os_resize_anonymous_file(fd, size) < 0) {
if (fd >= 0 && os_resize_anonymous_file(fd, size) < 0){
close(fd);
return -1;
fd = -1;
}
return fd;
return(fd);
}
//#include "plugins/gtk/libdecor-gtk.c"
struct find_widget_variables{
char *name;
GtkWidget *widget;
} find_widget_variables;
static void
gtk_fill_widget_from_name(GtkWidget *widget, void *data){
fill_widget_from_name(GtkWidget *widget, void *data){
struct find_widget_variables *vars = data;
if (vars->widget == 0){
bool match = false;
if (GTK_IS_WIDGET(widget)){
struct header_element_data *elem = data;
GtkStyleContext *style_context = gtk_widget_get_style_context(widget);
char *style_ctx = gtk_style_context_to_string(style_context, GTK_STYLE_CONTEXT_PRINT_SHOW_STYLE);
if (strstr(style_ctx, elem->name) != 0){
elem->widget = widget;
char *style_str = gtk_style_context_to_string(style_context, GTK_STYLE_CONTEXT_PRINT_SHOW_STYLE);
if (strstr(style_str, vars->name) != 0){
vars->widget = widget;
match = true;
}
free(style_ctx);
free(style_str);
}
/* recursively traverse container */
if (!match && GTK_IS_CONTAINER(widget)){
gtk_container_forall(GTK_CONTAINER(widget), &gtk_fill_widget_from_name, data);
gtk_container_forall(GTK_CONTAINER(widget), &fill_widget_from_name, data);
}
}
}
static struct header_element_data
find_widget_by_type(GtkWidget *widget, enum header_element type){
char* name = 0;
static GtkWidget*
find_widget_by_type(GtkWidget *root, enum header_element type){
struct find_widget_variables vars = {0};
switch (type){
case HEADER_FULL: name = "headerbar.titlebar:"; break;
case HEADER_TITLE: name = "label.title:"; break;
case HEADER_MIN: name = ".minimize"; break;
case HEADER_MAX: name = ".maximize"; break;
case HEADER_CLOSE: name = ".close"; break;
case HEADER_FULL: vars.name = "headerbar.titlebar:"; break;
case HEADER_TITLE: vars.name = "label.title:"; break;
case HEADER_MIN: vars.name = ".minimize"; break;
case HEADER_MAX: vars.name = ".maximize"; break;
case HEADER_CLOSE: vars.name = ".close"; break;
default:break;
}
struct header_element_data data = {0};
data.name = name;
data.type = type;
gtk_fill_widget_from_name(widget, &data);
return(data);
fill_widget_from_name(root, &vars);
return(vars.widget);
}
static struct header_element_data
@ -1748,13 +1696,14 @@ get_header_focus(const GtkHeaderBar *header_bar, int x, int y){
struct header_element_data result = {0};
for (size_t i = 0; i < ARRAY_LENGTH(elems); i += 1){
struct header_element_data elem = find_widget_by_type(GTK_WIDGET(header_bar), elems[i]);
if (elem.widget){
GtkWidget *widget = find_widget_by_type(GTK_WIDGET(header_bar), elems[i]);
if (widget != 0){
GtkAllocation allocation;
gtk_widget_get_allocation(GTK_WIDGET(elem.widget), &allocation);
gtk_widget_get_allocation(GTK_WIDGET(widget), &allocation);
if (allocation.x <= x && x < allocation.x + allocation.width &&
allocation.y <= y && y < allocation.y + allocation.height){
result = elem;
result.type = elems[i];
result.widget = widget;
break;
}
}
@ -1897,10 +1846,7 @@ array_append(enum header_element **array, size_t *n, enum header_element item){
static void
draw_header_button(cairo_t *cr, cairo_surface_t *surface,
enum header_element button_type){
struct header_element_data elem;
GtkWidget *button;
GtkStyleContext* button_style;
GtkStateFlags style_state;
GtkAllocation allocation;
@ -1922,11 +1868,10 @@ draw_header_button(cairo_t *cr, cairo_surface_t *surface,
GtkBorder border;
GtkBorder padding;
elem = find_widget_by_type(ctx.header, button_type);
button = elem.widget;
button = find_widget_by_type(ctx.header, button_type);
if (button){
button_style = gtk_widget_get_style_context(button);
style_state = elem.state;
GtkStyleContext *button_style = gtk_widget_get_style_context(button);
GtkStateFlags style_state = 0;
/* change style based on window state and focus */
if (!(ctx.frame_window_state & LIBDECOR_WINDOW_STATE_ACTIVE)){
@ -1934,7 +1879,7 @@ draw_header_button(cairo_t *cr, cairo_surface_t *surface,
}
if (ctx.hdr_focus.widget == button){
style_state |= GTK_STATE_FLAG_PRELIGHT;
if (ctx.hdr_focus.state & GTK_STATE_FLAG_ACTIVE) {
if (ctx.hdr_state & GTK_STATE_FLAG_ACTIVE){
style_state |= GTK_STATE_FLAG_ACTIVE;
}
}
@ -2037,7 +1982,7 @@ static void
draw_border_component(enum component_slot slot){
if (slot < COMPONENT_SLOT_COUNT &&
ctx.component_slot[slot].wl_surface != 0){
Extent2D extent = extent2d_from_component_slot(slot);
struct border_component *component = &ctx.component_slot[slot];
if (slot == COMPONENT_SLOT_SHADOW && ctx.shadow_showing){
struct wl_region *input_region;
@ -2045,26 +1990,25 @@ draw_border_component(enum component_slot slot){
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.frame_content_width, ctx.frame_content_height);
wl_surface_set_input_region(ctx.component_slot[slot].wl_surface, input_region);
wl_surface_set_input_region(component->wl_surface, input_region);
wl_region_destroy(input_region);
}
struct border_component *component = &ctx.component_slot[slot];
{
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->wl_buffer = 0;
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;
@ -2125,7 +2069,7 @@ draw_border_component(enum component_slot slot){
/* title */
{
GtkWidget *label = find_widget_by_type(ctx.header, HEADER_TITLE).widget;
GtkWidget *label = find_widget_by_type(ctx.header, HEADER_TITLE);
GtkAllocation allocation;
gtk_widget_get_allocation(label, &allocation);
@ -2182,11 +2126,7 @@ draw_border_component(enum component_slot slot){
static void
draw_title_bar(void){
enum libdecor_window_state state;
GtkStyleContext *style;
state = ctx.frame_window_state;
style = gtk_widget_get_style_context(ctx.window);
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);
@ -2194,14 +2134,13 @@ draw_title_bar(void){
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;
@ -2327,8 +2266,9 @@ update_touch_focus(struct seat *seat, wl_fixed_t x, wl_fixed_t y){
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;
ctx.hdr_state = 0;
}
ctx.hdr_focus.state |= GTK_STATE_FLAG_PRELIGHT;
ctx.hdr_state |= GTK_STATE_FLAG_PRELIGHT;
draw_title_bar();
wl_surface_commit(ctx.wl_surface);
}

View File

@ -147,10 +147,8 @@ enum titlebar_gesture_state {
};
struct header_element_data{
const char *name;
enum header_element type;
GtkWidget *widget;
GtkStateFlags state;
};
enum decoration_type {
@ -253,8 +251,6 @@ enum titlebar_gesture {
void libdecor_frame_show_window_menu(struct wl_seat *wl_seat, uint32_t serial, int x, int y);
void libdecor_frame_commit(void);
void libdecor_frame_set_fullscreen(struct wl_output *output);
void libdecor_frame_unset_fullscreen(void);
// #include "libdecor-cairo-blur.h"
@ -281,8 +277,6 @@ 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(void);
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);
@ -386,6 +380,7 @@ typedef struct Ctx{
GtkWidget *window;
GtkWidget *header;
struct header_element_data hdr_focus;
GtkStateFlags hdr_state;
cairo_surface_t *shadow_blur;