[digesting_libdecor] extract redraw logic from each event path and just run once per frame (this introduces a bug with the title bar button highlights, will have to fix after simplifications are finished, not clear how to avoid incrementally)

main
Allen Webster 2026-03-02 14:27:41 -08:00
parent 107aa41329
commit 59031ef536
2 changed files with 127 additions and 169 deletions

View File

@ -345,6 +345,8 @@ const struct zxdg_toplevel_decoration_v1_listener
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);
int main(){
/* get desktop settings */
@ -650,7 +652,17 @@ int main(){
}
/* re-render cursor */
ctx.seat->current_cursor = wl_cursor_from_pos(ctx.seat->pointer_x, ctx.seat->pointer_y);
{
struct wl_cursor *cursor = ctx.cursor_left_ptr;
if (ctx.active == COMPONENT_SLOT_SHADOW &&
(ctx.frame_capabilities & LIBDECOR_ACTION_RESIZE)){
enum libdecor_resize_edge edge = edge_from_pos(ctx.seat->pointer_x, ctx.seat->pointer_y);
if (edge != LIBDECOR_RESIZE_EDGE_NONE){
cursor = ctx.cursors[edge - 1];
}
}
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);
@ -667,16 +679,10 @@ int main(){
ctx.titlebar_gesture.first_pressed_button = 0;
ctx.hdr_focus.widget = 0;
ctx.hdr_focus.type = HEADER_NONE;
draw_decoration();
wl_surface_commit(ctx.wl_surface);
}
if (ctx.pointer_enter){
ctx.pointer_enter = 0;
if (ctx.active != 0){
draw_decoration();
wl_surface_commit(ctx.wl_surface);
}
}
if (ctx.pointer_motion){
@ -720,9 +726,6 @@ int main(){
}
}
}
draw_title_bar();
wl_surface_commit(ctx.wl_surface);
}
if (ctx.pointer_button){
@ -757,8 +760,7 @@ int main(){
xdg_toplevel_show_window_menu(ctx.xdg_toplevel, ctx.seat->wl_seat, ctx.seat->serial, ctx.seat->pointer_x, -title_height);
ctx.titlebar_gesture.state = TITLEBAR_GESTURE_STATE_CONSUMED;
}
else{
if (ctx.pointer_button_button == BTN_LEFT &&
else if (ctx.pointer_button_button == BTN_LEFT &&
ctx.titlebar_gesture.first_pressed_button == BTN_LEFT &&
ctx.pointer_button_time - ctx.titlebar_gesture.first_pressed_time < (uint32_t)ctx.double_click_time_ms){
if ((ctx.frame_capabilities & LIBDECOR_ACTION_RESIZE)){
@ -774,19 +776,13 @@ int main(){
ctx.titlebar_gesture.serial = ctx.seat->serial;
ctx.titlebar_gesture.state = TITLEBAR_GESTURE_STATE_BUTTON_PRESSED;
}
}
ctx.titlebar_gesture.button_pressed_count = 1;
switch (ctx.hdr_focus.type){
case HEADER_MIN:
case HEADER_MAX:
case HEADER_CLOSE: {
ctx.hdr_focus_is_active = 1;
draw_title_bar();
wl_surface_commit(ctx.wl_surface);
}break;
case HEADER_CLOSE: ctx.hdr_focus_is_active = 1; break;
default: break;
}
}
@ -833,11 +829,6 @@ int main(){
else{
ctx.hdr_focus_is_active = 0;
}
if (GTK_IS_WIDGET(ctx.header)) {
draw_title_bar();
wl_surface_commit(ctx.wl_surface);
}
}
}break;
@ -859,13 +850,10 @@ int main(){
default: break;
}
}
/* apply new surface config */
if (ctx.has_cached_config){
ctx.has_cached_config = 0;
if (ctx.cached_config.initialized){
ctx.frame_window_state = ctx.cached_config.window_state;
}
@ -900,8 +888,13 @@ int main(){
ctx.w = w;
ctx.h = h;
}
}
frame_commit();
wl_surface_commit(ctx.wl_surface);
if (ctx.has_cached_config){
ctx.has_cached_config = 0;
xdg_surface_ack_configure(ctx.xdg_surface, ctx.cached_config.serial);
}
@ -978,6 +971,14 @@ decoration_type_from_window_state(enum libdecor_window_state window_state){
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;
@ -997,12 +998,8 @@ frame_commit(void){
}
else{
int csd_added_w = 0;
int csd_added_h = 0;
if (csd){
csd_added_w = border_size.x[0] + border_size.x[1];
csd_added_h = border_size.y[0] + border_size.y[1];
}
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;
@ -1021,9 +1018,76 @@ frame_commit(void){
if (csd){
ctx.decoration_type = decoration_type_from_window_state(ctx.frame_window_state);
draw_decoration();
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);
@ -1031,29 +1095,19 @@ frame_commit(void){
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;
}
memset(ctx.component_slot, 0, sizeof ctx.component_slot);
ctx.shadow_showing = false;
g_clear_pointer(&ctx.title, free);
ctx.decoration_type = DECORATION_TYPE_NONE;
}
{
@ -1066,7 +1120,6 @@ frame_commit(void){
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);
}
}
@ -1459,14 +1512,6 @@ toggle_maximized(void){
}
}
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);
}
}
static enum component_slot
component_slot_from_wl_surface(const struct wl_surface *surface){
enum component_slot result = 0;
@ -1490,8 +1535,6 @@ ensure_component(struct border_component *cmpnt){
static void
ensure_title_bar_surfaces(void){
GtkStyleContext *context_hdr;
ctx.component_slot[COMPONENT_SLOT_HEADER].opaque = false;
ensure_component(&ctx.component_slot[COMPONENT_SLOT_HEADER]);
@ -1521,7 +1564,7 @@ ensure_title_bar_surfaces(void){
"show-close-button", TRUE,
NULL);
context_hdr = gtk_widget_get_style_context(ctx.header);
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");
@ -1564,8 +1607,6 @@ extent2d_from_component_slot(enum component_slot slot){
static void
draw_header_button(cairo_t *cr, cairo_surface_t *surface,
enum header_element button_type){
GtkWidget *button;
GtkAllocation allocation;
gchar *icon_name;
@ -1574,7 +1615,8 @@ draw_header_button(cairo_t *cr, cairo_surface_t *surface,
GtkAllocation allocation_icon;
GtkIconInfo* icon_info;
double sx, sy;
double sx;
double sy;
gint icon_width, icon_height;
@ -1586,12 +1628,12 @@ draw_header_button(cairo_t *cr, cairo_surface_t *surface,
GtkBorder border;
GtkBorder padding;
button = find_widget_by_type(ctx.header, button_type);
if (button){
GtkWidget *button = find_widget_by_type(ctx.header, button_type);
if (button != 0){
GtkStyleContext *button_style = gtk_widget_get_style_context(button);
GtkStateFlags style_state = 0;
/* change style based on window state and focus */
GtkStateFlags style_state = 0;
if (!(ctx.frame_window_state & LIBDECOR_WINDOW_STATE_ACTIVE)){
style_state |= GTK_STATE_FLAG_BACKDROP;
}
@ -1622,9 +1664,9 @@ draw_header_button(cairo_t *cr, cairo_surface_t *surface,
}break;
case HEADER_MAX:{
icon_name = (ctx.frame_window_state & LIBDECOR_WINDOW_STATE_MAXIMIZED) ?
icon_name = ((ctx.frame_window_state & LIBDECOR_WINDOW_STATE_MAXIMIZED) ?
"window-restore-symbolic" :
"window-maximize-symbolic";
"window-maximize-symbolic");
}break;
case HEADER_CLOSE: {
@ -1655,14 +1697,14 @@ draw_header_button(cairo_t *cr, cairo_surface_t *surface,
/* icon pixel buffer*/
gtk_style_context_save(button_style);
gtk_style_context_set_state(button_style, style_state);
icon_pixbuf = gtk_icon_info_load_symbolic_for_context(
icon_info, button_style, NULL, NULL);
icon_pixbuf = gtk_icon_info_load_symbolic_for_context(icon_info, button_style, 0, 0);
icon_surface = gdk_cairo_surface_create_from_pixbuf(icon_pixbuf, scale, NULL);
gtk_style_context_restore(button_style);
/* dimensions and position */
gtk_style_context_get(button_style, gtk_style_context_get_state(button_style),
"min-width", &width, "min-height", &height, NULL);
"min-width", &width,
"min-height", &height, NULL);
if (width < icon_width){
width = icon_width;
@ -1842,76 +1884,6 @@ draw_border_component(enum component_slot slot){
}
}
static void
draw_title_bar(void){
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);
}
}
static void
draw_decoration(void){
switch (ctx.decoration_type){
case DECORATION_TYPE_NONE: {
hide_border_component(&ctx.component_slot[COMPONENT_SLOT_SHADOW]);
ctx.shadow_showing = false;
hide_border_component(&ctx.component_slot[COMPONENT_SLOT_HEADER]);
}break;
case DECORATION_TYPE_ALL: {
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;
ensure_title_bar_surfaces();
draw_title_bar();
}break;
case DECORATION_TYPE_TITLE_ONLY: {
hide_border_component(&ctx.component_slot[COMPONENT_SLOT_SHADOW]);
ctx.shadow_showing = false;
ensure_title_bar_surfaces();
draw_title_bar();
}break;
}
}
static Sides2D
border_size_from_window_state(enum libdecor_window_state window_state){
Sides2D border_size = {0};
@ -1960,19 +1932,6 @@ edge_from_pos(int x, int y){
return(result);
}
static struct wl_cursor *
wl_cursor_from_pos(int x, int y){
struct wl_cursor *result = ctx.cursor_left_ptr;
if (ctx.active == COMPONENT_SLOT_SHADOW &&
(ctx.frame_capabilities & LIBDECOR_ACTION_RESIZE)){
enum libdecor_resize_edge edge = edge_from_pos(x, y);
if (edge != LIBDECOR_RESIZE_EDGE_NONE){
result = ctx.cursors[edge - 1];
}
}
return(result);
}
//#include "desktop-settings.c"
static bool

View File

@ -270,7 +270,6 @@ 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_decoration(void);
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);