From bfacfc107fc4d4dd01fd594b6b60b928e86b4b49 Mon Sep 17 00:00:00 2001 From: Consolatis <35009135+Consolatis@users.noreply.github.com> Date: Thu, 24 Aug 2023 00:16:12 +0200 Subject: [PATCH] [wip] move ssd_button related things into own file --- include/node.h | 9 ++ include/ssd-internal.h | 7 +- src/desktop.c | 1 + src/node.c | 9 ++ src/ssd/meson.build | 5 +- src/ssd/ssd_button.c | 187 +++++++++++++++++++++++++++++++++++++++++ src/ssd/ssd_part.c | 130 ---------------------------- src/ssd/ssd_titlebar.c | 30 +++---- 8 files changed, 226 insertions(+), 152 deletions(-) create mode 100644 src/ssd/ssd_button.c diff --git a/include/node.h b/include/node.h index 419aa996..f973c360 100644 --- a/include/node.h +++ b/include/node.h @@ -18,6 +18,7 @@ enum node_descriptor_type { LAB_NODE_DESC_MENUITEM, LAB_NODE_DESC_TREE, LAB_NODE_DESC_SSD_BUTTON, + LAB_NODE_DESC_SSD_ROUNDED, }; struct node_descriptor { @@ -79,4 +80,12 @@ struct menuitem *node_menuitem_from_node( struct ssd_button *node_ssd_button_from_node( struct wlr_scene_node *wlr_scene_node); +/** + * node_ssd_rounded_from_node - return ssd_rounded struct from node + * @wlr_scene_node: wlr_scene_node from which to return data + */ +struct ssd_rounded; +struct ssd_rounded *node_ssd_rounded_from_node( + struct wlr_scene_node *wlr_scene_node); + #endif /* LABWC_NODE_DESCRIPTOR_H */ diff --git a/include/ssd-internal.h b/include/ssd-internal.h index 148337ed..21f35d46 100644 --- a/include/ssd-internal.h +++ b/include/ssd-internal.h @@ -111,15 +111,18 @@ struct ssd_part *add_scene_rect( struct ssd_part *add_scene_buffer( struct wl_list *list, enum ssd_part_type type, struct wlr_scene_tree *parent, struct wlr_buffer *buffer, int x, int y); -struct ssd_part *add_scene_button( + +/* SSD button */ +struct ssd_part *ssd_button_add( struct wl_list *part_list, enum ssd_part_type type, struct wlr_scene_tree *parent, float *bg_color, struct wlr_buffer *icon_buffer, int x, struct view *view); -struct ssd_part *add_scene_button_corner( +struct ssd_part *ssd_button_add_corner( struct wl_list *part_list, enum ssd_part_type type, enum ssd_part_type corner_type, struct wlr_scene_tree *parent, struct wlr_buffer *corner_buffer, struct wlr_buffer *icon_buffer, int x, struct view *view); +void ssd_button_enable_rounded_corner(struct ssd_part *ssd_part, float *color, bool enable); /* SSD internal helpers */ struct ssd_part *ssd_get_part( diff --git a/src/desktop.c b/src/desktop.c index c5a6657e..a1a04fc8 100644 --- a/src/desktop.c +++ b/src/desktop.c @@ -384,6 +384,7 @@ get_cursor_context(struct server *server) return ret; case LAB_NODE_DESC_NODE: case LAB_NODE_DESC_TREE: + case LAB_NODE_DESC_SSD_ROUNDED: break; } } diff --git a/src/node.c b/src/node.c index 84ca3f6c..31131205 100644 --- a/src/node.c +++ b/src/node.c @@ -79,3 +79,12 @@ node_ssd_button_from_node(struct wlr_scene_node *wlr_scene_node) assert(node_descriptor->type == LAB_NODE_DESC_SSD_BUTTON); return (struct ssd_button *)node_descriptor->data; } + +struct ssd_rounded * +node_ssd_rounded_from_node(struct wlr_scene_node *wlr_scene_node) +{ + assert(wlr_scene_node->data); + struct node_descriptor *node_descriptor = wlr_scene_node->data; + assert(node_descriptor->type == LAB_NODE_DESC_SSD_ROUNDED); + return (struct ssd_rounded *)node_descriptor->data; +} diff --git a/src/ssd/meson.build b/src/ssd/meson.build index b1a2a2fc..a70b537b 100644 --- a/src/ssd/meson.build +++ b/src/ssd/meson.build @@ -1,8 +1,9 @@ labwc_sources += files( 'resize_indicator.c', 'ssd.c', + 'ssd_border.c', + 'ssd_button.c', + 'ssd_extents.c', 'ssd_part.c', 'ssd_titlebar.c', - 'ssd_border.c', - 'ssd_extents.c', ) diff --git a/src/ssd/ssd_button.c b/src/ssd/ssd_button.c new file mode 100644 index 00000000..96060381 --- /dev/null +++ b/src/ssd/ssd_button.c @@ -0,0 +1,187 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include +#include +#include +#include "common/mem.h" +#include "common/scene-helpers.h" +#include "config/rcxml.h" +#include "labwc.h" /* for MIN() */ +#include "node.h" +#include "ssd-internal.h" + +struct ssd_rounded { + struct ssd_button *button; + struct wlr_scene_node *node; + + struct wl_listener destroy; +}; + +static void +ssd_button_destroy_notify(struct wl_listener *listener, void *data) +{ + struct ssd_button *button = wl_container_of(listener, button, destroy); + wl_list_remove(&button->destroy.link); + free(button); +} + +/* + * Create a new node_descriptor containing a link to a new ssd_button struct. + * Both will be destroyed automatically once the scene_node they are attached + * to is destroyed. + */ +static struct ssd_button * +ssd_button_descriptor_create(struct wlr_scene_node *node) +{ + /* Create new ssd_button */ + struct ssd_button *button = znew(*button); + + /* Let it destroy automatically when the scene node destroys */ + button->destroy.notify = ssd_button_destroy_notify; + wl_signal_add(&node->events.destroy, &button->destroy); + + /* And finally attach the ssd_button to a node descriptor */ + node_descriptor_create(node, LAB_NODE_DESC_SSD_BUTTON, button); + return button; +} + +static void +ssd_rounded_destroy_notify(struct wl_listener *listener, void *data) +{ + struct ssd_rounded *rounded = wl_container_of(listener, rounded, destroy); + wl_list_remove(&rounded->destroy.link); + free(rounded); +} + +static struct ssd_rounded * +ssd_rounded_descriptor_create(struct wlr_scene_node *node) +{ + struct ssd_rounded *rounded = znew(*rounded); + rounded->destroy.notify = ssd_rounded_destroy_notify; + wl_signal_add(&node->events.destroy, &rounded->destroy); + node_descriptor_create(node, LAB_NODE_DESC_SSD_ROUNDED, rounded); + return rounded; +} + +static struct wlr_box +get_scale_box(struct wlr_buffer *buffer, double container_width, double container_height) +{ + struct wlr_box icon_geo = { + .width = buffer->width, + .height = buffer->height + }; + + /* Scale down buffer if required */ + if (icon_geo.width && icon_geo.height) { + double scale = MIN(container_width / icon_geo.width, + container_height / icon_geo.height); + if (scale < 1.0f) { + icon_geo.width = (double)icon_geo.width * scale; + icon_geo.height = (double)icon_geo.height * scale; + } + } + + /* Center buffer on both axis */ + icon_geo.x = (container_width - icon_geo.width) / 2; + icon_geo.y = (container_height - icon_geo.height) / 2; + + return icon_geo; +} + +struct ssd_part * +ssd_button_add_corner(struct wl_list *part_list, enum ssd_part_type type, + enum ssd_part_type corner_type, struct wlr_scene_tree *parent, + struct wlr_buffer *corner_buffer, struct wlr_buffer *icon_buffer, + int x, struct view *view) +{ + int offset_x; + float invisible[4] = { 0, 0, 0, 0 }; + + if (corner_type == LAB_SSD_PART_CORNER_TOP_LEFT) { + offset_x = rc.theme->border_width; + } else if (corner_type == LAB_SSD_PART_CORNER_TOP_RIGHT) { + offset_x = 0; + } else { + assert(false && "invalid corner button type"); + } + + struct ssd_part *button_corner_root = add_scene_part(part_list, corner_type); + parent = wlr_scene_tree_create(parent); + button_corner_root->node = &parent->node; + wlr_scene_node_set_position(button_corner_root->node, x, 0); + + /* + * Background, x and y adjusted for border_width which is + * already included in rendered theme.c / corner_buffer + */ + struct ssd_part *button_rounded = add_scene_buffer(part_list, corner_type, + parent, corner_buffer, -offset_x, -rc.theme->border_width); + + /* Finally just put a usual theme button on top, using an invisible hitbox */ + struct ssd_part *button_part = + ssd_button_add(part_list, type, parent, invisible, icon_buffer, 0, view); + + /* And store the rounded corner scene node */ + struct ssd_button *ssd_button = node_ssd_button_from_node(button_part->node); + struct ssd_rounded *rounded = ssd_rounded_descriptor_create(button_corner_root->node); + rounded->node = button_rounded->node; + rounded->button = ssd_button; + + return button_corner_root; +} + +struct ssd_part * +ssd_button_add(struct wl_list *part_list, enum ssd_part_type type, + struct wlr_scene_tree *parent, float *bg_color, + struct wlr_buffer *icon_buffer, int x, struct view *view) +{ + struct wlr_scene_node *hover; + float hover_bg[4] = {0.15f, 0.15f, 0.15f, 0.3f}; + + struct ssd_part *button_root = add_scene_part(part_list, type); + parent = wlr_scene_tree_create(parent); + button_root->node = &parent->node; + wlr_scene_node_set_position(button_root->node, x, 0); + + /* Background */ + struct ssd_part *bg_rect = add_scene_rect(part_list, type, parent, + SSD_BUTTON_WIDTH, rc.theme->title_height, 0, 0, bg_color); + + /* Icon */ + struct wlr_box icon_geo = get_scale_box(icon_buffer, + SSD_BUTTON_WIDTH, rc.theme->title_height); + struct ssd_part *icon_part = add_scene_buffer(part_list, type, + parent, icon_buffer, icon_geo.x, icon_geo.y); + + /* Make sure big icons are scaled down if necessary */ + wlr_scene_buffer_set_dest_size( + wlr_scene_buffer_from_node(icon_part->node), + icon_geo.width, icon_geo.height); + + /* Hover overlay */ + hover = add_scene_rect(part_list, type, parent, SSD_BUTTON_WIDTH, + rc.theme->title_height, 0, 0, hover_bg)->node; + wlr_scene_node_set_enabled(hover, false); + + struct ssd_button *button = ssd_button_descriptor_create(button_root->node); + button->type = type; + button->view = view; + button->hover = hover; + button->background = bg_rect->node; + return button_root; +} + +void +ssd_button_enable_rounded_corner(struct ssd_part *corner_tree, float *bg_color, bool enable) +{ + assert(corner_tree); + + struct ssd_rounded *rounded = node_ssd_rounded_from_node(corner_tree->node); + + /* Toggle background between invisible and titlebar background color */ + struct wlr_scene_rect *rect = lab_wlr_scene_get_rect(rounded->button->background); + wlr_scene_rect_set_color(rect, enable ? (float[4]) {0, 0, 0, 0} : bg_color); + + /* Toggle rounded corner image itself */ + wlr_scene_node_set_enabled(rounded->node, enable); +} diff --git a/src/ssd/ssd_part.c b/src/ssd/ssd_part.c index 4c72d291..92312ca4 100644 --- a/src/ssd/ssd_part.c +++ b/src/ssd/ssd_part.c @@ -7,35 +7,6 @@ #include "node.h" #include "ssd-internal.h" -/* Internal helpers */ -static void -ssd_button_destroy_notify(struct wl_listener *listener, void *data) -{ - struct ssd_button *button = wl_container_of(listener, button, destroy); - wl_list_remove(&button->destroy.link); - free(button); -} - -/* - * Create a new node_descriptor containing a link to a new ssd_button struct. - * Both will be destroyed automatically once the scene_node they are attached - * to is destroyed. - */ -static struct ssd_button * -ssd_button_descriptor_create(struct wlr_scene_node *node) -{ - /* Create new ssd_button */ - struct ssd_button *button = znew(*button); - - /* Let it destroy automatically when the scene node destroys */ - button->destroy.notify = ssd_button_destroy_notify; - wl_signal_add(&node->events.destroy, &button->destroy); - - /* And finally attach the ssd_button to a node descriptor */ - node_descriptor_create(node, LAB_NODE_DESC_SSD_BUTTON, button); - return button; -} - /* Internal API */ struct ssd_part * add_scene_part(struct wl_list *part_list, enum ssd_part_type type) @@ -78,107 +49,6 @@ add_scene_buffer(struct wl_list *list, enum ssd_part_type type, return part; } -struct ssd_part * -add_scene_button_corner(struct wl_list *part_list, enum ssd_part_type type, - enum ssd_part_type corner_type, struct wlr_scene_tree *parent, - struct wlr_buffer *corner_buffer, struct wlr_buffer *icon_buffer, - int x, struct view *view) -{ - int offset_x; - float invisible[4] = { 0, 0, 0, 0 }; - - if (corner_type == LAB_SSD_PART_CORNER_TOP_LEFT) { - offset_x = rc.theme->border_width; - } else if (corner_type == LAB_SSD_PART_CORNER_TOP_RIGHT) { - offset_x = 0; - } else { - assert(false && "invalid corner button type"); - } - - struct ssd_part *button_root = add_scene_part(part_list, corner_type); - parent = wlr_scene_tree_create(parent); - button_root->node = &parent->node; - wlr_scene_node_set_position(button_root->node, x, 0); - - /* - * Background, x and y adjusted for border_width which is - * already included in rendered theme.c / corner_buffer - */ - add_scene_buffer(part_list, corner_type, parent, corner_buffer, - -offset_x, -rc.theme->border_width); - - /* Finally just put a usual theme button on top, using an invisible hitbox */ - add_scene_button(part_list, type, parent, invisible, icon_buffer, 0, view); - return button_root; -} - -static struct wlr_box -get_scale_box(struct wlr_buffer *buffer, double container_width, - double container_height) -{ - struct wlr_box icon_geo = { - .width = buffer->width, - .height = buffer->height - }; - - /* Scale down buffer if required */ - if (icon_geo.width && icon_geo.height) { - double scale = MIN(container_width / icon_geo.width, - container_height / icon_geo.height); - if (scale < 1.0f) { - icon_geo.width = (double)icon_geo.width * scale; - icon_geo.height = (double)icon_geo.height * scale; - } - } - - /* Center buffer on both axis */ - icon_geo.x = (container_width - icon_geo.width) / 2; - icon_geo.y = (container_height - icon_geo.height) / 2; - - return icon_geo; -} - -struct ssd_part * -add_scene_button(struct wl_list *part_list, enum ssd_part_type type, - struct wlr_scene_tree *parent, float *bg_color, - struct wlr_buffer *icon_buffer, int x, struct view *view) -{ - struct wlr_scene_node *hover; - float hover_bg[4] = {0.15f, 0.15f, 0.15f, 0.3f}; - - struct ssd_part *button_root = add_scene_part(part_list, type); - parent = wlr_scene_tree_create(parent); - button_root->node = &parent->node; - wlr_scene_node_set_position(button_root->node, x, 0); - - /* Background */ - struct ssd_part *bg_rect = add_scene_rect(part_list, type, parent, - SSD_BUTTON_WIDTH, rc.theme->title_height, 0, 0, bg_color); - - /* Icon */ - struct wlr_box icon_geo = get_scale_box(icon_buffer, - SSD_BUTTON_WIDTH, rc.theme->title_height); - struct ssd_part *icon_part = add_scene_buffer(part_list, type, - parent, icon_buffer, icon_geo.x, icon_geo.y); - - /* Make sure big icons are scaled down if necessary */ - wlr_scene_buffer_set_dest_size( - wlr_scene_buffer_from_node(icon_part->node), - icon_geo.width, icon_geo.height); - - /* Hover overlay */ - hover = add_scene_rect(part_list, type, parent, SSD_BUTTON_WIDTH, - rc.theme->title_height, 0, 0, hover_bg)->node; - wlr_scene_node_set_enabled(hover, false); - - struct ssd_button *button = ssd_button_descriptor_create(button_root->node); - button->type = type; - button->view = view; - button->hover = hover; - button->background = bg_rect->node; - return button_root; -} - struct ssd_part * ssd_get_part(struct wl_list *part_list, enum ssd_part_type type) { diff --git a/src/ssd/ssd_titlebar.c b/src/ssd/ssd_titlebar.c index b07b2b35..70778cf4 100644 --- a/src/ssd/ssd_titlebar.c +++ b/src/ssd/ssd_titlebar.c @@ -67,16 +67,16 @@ ssd_titlebar_create(struct ssd *ssd) width - SSD_BUTTON_WIDTH * SSD_BUTTON_COUNT, theme->title_height, SSD_BUTTON_WIDTH, 0, color); /* Buttons */ - add_scene_button_corner(&subtree->parts, + ssd_button_add_corner(&subtree->parts, LAB_SSD_BUTTON_WINDOW_MENU, LAB_SSD_PART_CORNER_TOP_LEFT, parent, corner_top_left, menu_button_unpressed, 0, view); - add_scene_button(&subtree->parts, LAB_SSD_BUTTON_ICONIFY, parent, + ssd_button_add(&subtree->parts, LAB_SSD_BUTTON_ICONIFY, parent, color, iconify_button_unpressed, width - SSD_BUTTON_WIDTH * 3, view); - add_scene_button(&subtree->parts, LAB_SSD_BUTTON_MAXIMIZE, parent, + ssd_button_add(&subtree->parts, LAB_SSD_BUTTON_MAXIMIZE, parent, color, maximize_button_unpressed, width - SSD_BUTTON_WIDTH * 2, view); - add_scene_button_corner(&subtree->parts, + ssd_button_add_corner(&subtree->parts, LAB_SSD_BUTTON_CLOSE, LAB_SSD_PART_CORNER_TOP_RIGHT, parent, corner_top_right, close_button_unpressed, width - SSD_BUTTON_WIDTH * 1, view); @@ -95,24 +95,18 @@ set_squared_corners(struct ssd *ssd, bool enable) { struct ssd_part *part; struct ssd_sub_tree *subtree; - enum ssd_part_type ssd_type[2] = { LAB_SSD_BUTTON_WINDOW_MENU, LAB_SSD_BUTTON_CLOSE }; + enum ssd_part_type ssd_type[2] = { + LAB_SSD_PART_CORNER_TOP_LEFT, + LAB_SSD_PART_CORNER_TOP_RIGHT + }; FOR_EACH_STATE(ssd, subtree) { + float *bg_color = subtree == &ssd->titlebar.active + ? rc.theme->window_active_title_bg_color + : rc.theme->window_inactive_title_bg_color; for (size_t i = 0; i < sizeof(ssd_type) / sizeof(ssd_type[0]); i++) { part = ssd_get_part(&subtree->parts, ssd_type[i]); - struct ssd_button *button = node_ssd_button_from_node(part->node); - - /* Toggle background between invisible and titlebar background color */ - struct wlr_scene_rect *rect = lab_wlr_scene_get_rect(button->background); - wlr_scene_rect_set_color(rect, !enable ? (float[4]) {0, 0, 0, 0} : ( - subtree == &ssd->titlebar.active - ? rc.theme->window_active_title_bg_color - : rc.theme->window_inactive_title_bg_color)); - - /* Toggle rounded corner image itself */ - struct wlr_scene_node *rounded_corner = - wl_container_of(part->node->link.prev, rounded_corner, link); - wlr_scene_node_set_enabled(rounded_corner, !enable); + ssd_button_enable_rounded_corner(part, bg_color, !enable); } } FOR_EACH_END