diff --git a/include/node.h b/include/node.h index e8d6535b..3e0601a5 100644 --- a/include/node.h +++ b/include/node.h @@ -7,6 +7,7 @@ struct view; struct lab_layer_surface; struct lab_layer_popup; struct menuitem; +struct ssd_button; enum node_descriptor_type { LAB_NODE_DESC_NODE = 0, @@ -27,6 +28,10 @@ struct node_descriptor { /** * node_descriptor_create - create node descriptor for wlr_scene_node user_data + * + * The node_descriptor will be destroyed automatically + * once the scene_node it is attached to is destroyed. + * * @scene_node: wlr_scene_node to attached node_descriptor to * @type: node descriptor type * @data: struct to point to as follows: @@ -34,6 +39,8 @@ struct node_descriptor { * - LAB_NODE_DESC_XDG_POPUP struct view * - LAB_NODE_DESC_LAYER_SURFACE struct lab_layer_surface * - LAB_NODE_DESC_LAYER_POPUP struct lab_layer_popup + * - LAB_NODE_DESC_MENUITEM struct menuitem + * - LAB_NODE_DESC_SSD_BUTTON struct ssd_button */ void node_descriptor_create(struct wlr_scene_node *scene_node, enum node_descriptor_type type, void *data); @@ -65,4 +72,11 @@ struct lab_layer_popup *node_layer_popup_from_node( struct menuitem *node_menuitem_from_node( struct wlr_scene_node *wlr_scene_node); +/** + * node_ssd_button_from_node - return ssd_button struct from node + * @wlr_scene_node: wlr_scene_node from which to return data + */ +struct ssd_button *node_ssd_button_from_node( + struct wlr_scene_node *wlr_scene_node); + #endif /* __LABWC_NODE_DESCRIPTOR_H */ diff --git a/include/ssd.h b/include/ssd.h index 0f9ff624..027dcc21 100644 --- a/include/ssd.h +++ b/include/ssd.h @@ -54,6 +54,14 @@ struct wl_list; struct wlr_box; struct wlr_scene_tree; +struct ssd_button { + struct view *view; + enum ssd_part_type type; + struct wlr_scene_node *hover; + + struct wl_listener destroy; +}; + struct ssd_sub_tree { struct wlr_scene_tree *tree; struct wl_list parts; /* ssd_part::link */ @@ -120,7 +128,6 @@ struct ssd_part { struct ssd_hover_state { struct view *view; - enum ssd_part_type type; struct wlr_scene_node *node; }; @@ -132,9 +139,8 @@ void ssd_update_title(struct view *view); void ssd_update_geometry(struct view *view); void ssd_reload(struct view *view); void ssd_destroy(struct view *view); -/* Returns hover overlay node so it can be disabled later on */ -struct wlr_scene_node *ssd_button_hover_enable( - struct view *view, enum ssd_part_type type); +void ssd_update_button_hover(struct wlr_scene_node *node, + struct ssd_hover_state *hover_state); /* Public SSD helpers */ enum ssd_part_type ssd_at(struct view *view, double lx, double ly); diff --git a/src/cursor.c b/src/cursor.c index 2527be9f..b248d083 100644 --- a/src/cursor.c +++ b/src/cursor.c @@ -274,25 +274,8 @@ process_cursor_motion(struct server *server, uint32_t time) } } - /* SSD button mouse-over */ - struct ssd_hover_state *hover = &server->ssd_hover_state; - if (ssd_is_button(view_area)) { - /* Cursor entered new button area */ - if (hover->view != view || hover->type != view_area) { - if (hover->node) { - wlr_scene_node_set_enabled(hover->node, false); - } - hover->view = view; - hover->type = view_area; - hover->node = ssd_button_hover_enable(view, view_area); - } - } else if (hover->node) { - /* Cursor left button area */ - wlr_scene_node_set_enabled(hover->node, false); - hover->view = NULL; - hover->type = LAB_SSD_NONE; - hover->node = NULL; - } + /* TODO: ssd_hover_state should likely be located in server->seat */ + ssd_update_button_hover(node, &server->ssd_hover_state); if (server->seat.pressed.surface && server->seat.pressed.surface != surface && diff --git a/src/desktop.c b/src/desktop.c index 30f38264..9e16465e 100644 --- a/src/desktop.c +++ b/src/desktop.c @@ -296,8 +296,10 @@ desktop_node_and_view_at(struct server *server, double lx, double ly, } if (desc->type == LAB_NODE_DESC_SSD_BUTTON) { /* Always return the top scene node for SSD buttons */ + struct ssd_button *button = node_ssd_button_from_node(node); *scene_node = node; - goto has_view_data; + *view_area = button->type; + return button->view; } if (desc->type == LAB_NODE_DESC_LAYER_SURFACE) { /* FIXME: we shouldn't have to set *view_area */ diff --git a/src/node.c b/src/node.c index 6386fc81..67c01a15 100644 --- a/src/node.c +++ b/src/node.c @@ -43,8 +43,7 @@ node_view_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_VIEW - || node_descriptor->type == LAB_NODE_DESC_XDG_POPUP - || node_descriptor->type == LAB_NODE_DESC_SSD_BUTTON); + || node_descriptor->type == LAB_NODE_DESC_XDG_POPUP); return (struct view *)node_descriptor->data; } @@ -74,3 +73,12 @@ node_menuitem_from_node(struct wlr_scene_node *wlr_scene_node) assert(node_descriptor->type == LAB_NODE_DESC_MENUITEM); return (struct menuitem *)node_descriptor->data; } + +struct ssd_button * +node_ssd_button_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_BUTTON); + return (struct ssd_button *)node_descriptor->data; +} diff --git a/src/ssd/ssd.c b/src/ssd/ssd.c index 97e804c6..94dcf501 100644 --- a/src/ssd/ssd.c +++ b/src/ssd/ssd.c @@ -240,7 +240,6 @@ ssd_destroy(struct view *view) hover_state = &view->server->ssd_hover_state; if (hover_state->view == view) { hover_state->view = NULL; - hover_state->type = LAB_SSD_NONE; hover_state->node = NULL; } diff --git a/src/ssd/ssd_part.c b/src/ssd/ssd_part.c index 95c3ab70..d060f08f 100644 --- a/src/ssd/ssd_part.c +++ b/src/ssd/ssd_part.c @@ -5,6 +5,36 @@ #include "ssd.h" #include "node.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 = calloc(1, sizeof(struct ssd_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) { @@ -85,17 +115,16 @@ 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 ssd_part *part; + 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); - node_descriptor_create(button_root->node, LAB_NODE_DESC_SSD_BUTTON, view); /* Background */ - part = add_scene_rect(part_list, type, parent, + add_scene_rect(part_list, type, parent, BUTTON_WIDTH, rc.theme->title_height, 0, 0, bg_color); /* Icon */ @@ -104,10 +133,14 @@ add_scene_button(struct wl_list *part_list, enum ssd_part_type type, (rc.theme->title_height - icon_buffer->height) / 2); /* Hover overlay */ - part = add_scene_rect(part_list, type, parent, BUTTON_WIDTH, - rc.theme->title_height, 0, 0, hover_bg); - wlr_scene_node_set_enabled(part->node, false); + hover = add_scene_rect(part_list, type, parent, 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; return button_root; } diff --git a/src/ssd/ssd_titlebar.c b/src/ssd/ssd_titlebar.c index 6c27943f..e741bf06 100644 --- a/src/ssd/ssd_titlebar.c +++ b/src/ssd/ssd_titlebar.c @@ -8,6 +8,7 @@ #include "theme.h" #include "common/font.h" #include "common/scene-helpers.h" +#include "node.h" #define FOR_EACH_STATE(view, tmp) FOR_EACH(tmp, \ &(view)->ssd.titlebar.active, \ @@ -271,52 +272,35 @@ ssd_update_title(struct view *view) ssd_update_title_positions(view); } -/* - * Returns the wlr_scene_node for hover effect. - * To disable the hover effect later on just call - * wlr_scene_node_set_enabled(node, false). - */ -struct wlr_scene_node * -ssd_button_hover_enable(struct view *view, enum ssd_part_type type) +void +ssd_update_button_hover(struct wlr_scene_node *node, + struct ssd_hover_state *hover_state) { - if (!view->ssd.tree) { - wlr_log(WLR_ERROR, "%s() for destroyed view", __func__); - return NULL; + struct ssd_button *button = NULL; + if (!node || !node->data) { + goto disable_old_hover; } - assert(ssd_is_button(type)); - struct ssd_part *part; - struct ssd_sub_tree *subtree; - FOR_EACH_STATE(view, subtree) { - if (subtree->tree->node.enabled) { - /* - * TODO: This function makes too many magic assumptions: - * - It expects the returned part to be the tree for the button - * - It expects the last node in that tree to be the hover overlay - * - * Both assumptions are valid as long as ssd_parts.c isn't changing - * the way a button is created but this cries for introducing bugs - * in the future if the button creation process or ssd_get_part() - * lookup routine would ever change. - */ - part = ssd_get_part(&subtree->parts, type); - if (!part) { - wlr_log(WLR_ERROR, "hover enable failed to find button"); - return NULL; - } - struct wlr_scene_node *child; - struct wlr_scene_tree *button = lab_scene_tree_from_node(part->node); - wl_list_for_each_reverse(child, &button->children, link) { - if (child->type == WLR_SCENE_NODE_RECT) { - wlr_scene_node_set_enabled(child, true); - return child; - } - } + struct node_descriptor *desc = node->data; + if (desc->type == LAB_NODE_DESC_SSD_BUTTON) { + button = node_ssd_button_from_node(node); + if (button->hover == hover_state->node) { + /* Cursor is still on the same button */ + return; } - } FOR_EACH_END + } - wlr_log(WLR_ERROR, "hover enable failed to find button"); - return NULL; +disable_old_hover: + if (hover_state->node) { + wlr_scene_node_set_enabled(hover_state->node, false); + hover_state->view = NULL; + hover_state->node = NULL; + } + if (button) { + wlr_scene_node_set_enabled(button->hover, true); + hover_state->view = button->view; + hover_state->node = button->hover; + } } #undef FOR_EACH_STATE