]> git.mdlowis.com Git - proto/labwc.git/commitdiff
ssd: dynamically adjust resize extents based on usable_area
authorConsolatis <35009135+Consolatis@users.noreply.github.com>
Thu, 10 Mar 2022 05:50:42 +0000 (06:50 +0100)
committerJohan Malm <johanmalm@users.noreply.github.com>
Sat, 12 Mar 2022 15:32:44 +0000 (15:32 +0000)
Fixes #265

include/ssd.h
src/ssd/ssd.c
src/ssd/ssd_extents.c
src/ssd/ssd_part.c
src/view.c

index a87df8df1f0636f36418e6773691c84a495de178..e3feee0a90e5fe4dffee2d8827a6ad4cf5fd4f48 100644 (file)
@@ -74,6 +74,8 @@ struct ssd {
         * don't update things we don't have to.
         */
        struct {
+               int x;
+               int y;
                int width;
                int height;
                struct ssd_state_title {
@@ -110,6 +112,9 @@ struct ssd_part {
        /* This part represented in scene graph */
        struct wlr_scene_node *node;
 
+       /* Targeted geometry. May be NULL */
+       struct wlr_box *geometry;
+
        struct wl_list link;
 };
 
index 902fd2d72b5ebfe4583a61422f1b8c031574a4ab..4c4e5990cdbfa26b60785ffd7414600b3b165b48 100644 (file)
@@ -155,28 +155,35 @@ ssd_create(struct view *view)
        view->ssd.tree = wlr_scene_tree_create(&view->scene_tree->node);
        wlr_scene_node_lower_to_bottom(&view->ssd.tree->node);
        ssd_extents_create(view);
-       ssd_titlebar_create(view);
        ssd_border_create(view);
+       ssd_titlebar_create(view);
 }
 
 void
 ssd_update_geometry(struct view *view)
 {
-       /* TODO: verify we are not called without reason. like in commit handlers */
        if (!view->ssd.tree || !view->scene_node) {
                return;
        }
 
-       if (view->ssd.enabled && !view->ssd.tree->node.state.enabled) {
+       if (!view->ssd.enabled) {
+               if (view->ssd.tree->node.state.enabled) {
+                       wlr_scene_node_set_enabled(&view->ssd.tree->node, false);
+               }
+               return;
+       } else if (!view->ssd.tree->node.state.enabled) {
                wlr_scene_node_set_enabled(&view->ssd.tree->node, true);
        }
-       if (!view->ssd.enabled && view->ssd.tree->node.state.enabled) {
-               wlr_scene_node_set_enabled(&view->ssd.tree->node, false);
-       }
 
        int width = view->w;
        int height = view->h;
        if (width == view->ssd.state.width && height == view->ssd.state.height) {
+               if (view->x != view->ssd.state.x || view->y != view->ssd.state.y) {
+                       /* Dynamically resize extents based on position and usable_area */
+                       ssd_extents_update(view);
+                       view->ssd.state.x = view->x;
+                       view->ssd.state.y = view->y;
+               }
                return;
        }
        ssd_extents_update(view);
@@ -185,6 +192,8 @@ ssd_update_geometry(struct view *view)
 
        view->ssd.state.width = width;
        view->ssd.state.height = height;
+       view->ssd.state.x = view->x;
+       view->ssd.state.y = view->y;
 }
 
 void
index 85f6e7ffd8f808bb86b78dea1f55c3f15c72cf5f..28e1993476da4241448fe3c978c586c7b7f9c1f2 100644 (file)
@@ -5,20 +5,40 @@
 #include "theme.h"
 #include "common/scene-helpers.h"
 
+static struct ssd_part *
+add_extent(struct wl_list *part_list, enum ssd_part_type type,
+               struct wlr_scene_node *parent)
+{
+       float invisible[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
+       struct ssd_part *part = add_scene_part(part_list, type);
+       /*
+        * Extents need additional geometry to enable dynamic
+        * resize based on position and output->usable_area.
+        *
+        * part->geometry will get free'd automatically in ssd_destroy_parts().
+        */
+       part->node = &wlr_scene_rect_create(parent, 0, 0, invisible)->node;
+       part->geometry = calloc(1, sizeof(struct wlr_box));
+       return part;
+}
+
+static void
+lab_wlr_output_layout_layout_coords(struct wlr_output_layout *layout,
+               struct wlr_output *output, int *x, int *y)
+{
+       struct wlr_output_layout_output *l_output;
+       l_output = wlr_output_layout_get(layout, output);
+       *x += l_output->x;
+       *y += l_output->y;
+}
+
 void
 ssd_extents_create(struct view *view)
 {
        struct theme *theme = view->server->theme;
-       float invisible[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
        struct wl_list *part_list = &view->ssd.extents.parts;
-       int width = view->w;
-       int height = view->h;
-       int full_height = height + theme->border_width * 2 + theme->title_height;
-       int full_width = width + theme->border_width * 2;
        int extended_area = EXTENDED_AREA;
        int corner_size = extended_area + theme->border_width + BUTTON_WIDTH / 2;
-       int side_width = full_width + extended_area * 2 - corner_size * 2;
-       int side_height = full_height + extended_area * 2 - corner_size * 2;
 
        view->ssd.extents.tree = wlr_scene_tree_create(&view->ssd.tree->node);
        struct wlr_scene_node *parent = &view->ssd.extents.tree->node;
@@ -29,35 +49,43 @@ ssd_extents_create(struct view *view)
        wlr_scene_node_set_position(parent, -(theme->border_width + extended_area),
                -(theme->title_height + theme->border_width + extended_area));
 
+       /* Initialize parts and set constant values for targeted geometry */
+       struct ssd_part *p;
+
        /* Top */
-       add_scene_rect(part_list, LAB_SSD_PART_CORNER_TOP_LEFT, parent,
-               corner_size, corner_size,
-               0, 0, invisible);
-       add_scene_rect(part_list, LAB_SSD_PART_TOP, parent,
-               side_width, extended_area,
-               corner_size, 0, invisible);
-       add_scene_rect(part_list, LAB_SSD_PART_CORNER_TOP_RIGHT, parent,
-               corner_size, corner_size,
-               corner_size + side_width, 0, invisible);
+       p = add_extent(part_list, LAB_SSD_PART_CORNER_TOP_LEFT, parent);
+       p->geometry->width = corner_size;
+       p->geometry->height = corner_size;
+
+       p = add_extent(part_list, LAB_SSD_PART_TOP, parent);
+       p->geometry->x = corner_size;
+       p->geometry->height = extended_area;
+
+       p = add_extent(part_list, LAB_SSD_PART_CORNER_TOP_RIGHT, parent);
+       p->geometry->width = corner_size;
+       p->geometry->height = corner_size;
 
        /* Sides */
-       add_scene_rect(part_list, LAB_SSD_PART_LEFT, parent,
-               extended_area, side_height,
-               0, corner_size, invisible);
-       add_scene_rect(part_list, LAB_SSD_PART_RIGHT, parent,
-               extended_area, side_height,
-               corner_size + side_width, corner_size, invisible);
+       p = add_extent(part_list, LAB_SSD_PART_LEFT, parent);
+       p->geometry->y = corner_size;
+       p->geometry->width = extended_area;
+
+       p = add_extent(part_list, LAB_SSD_PART_RIGHT, parent);
+       p->geometry->y = corner_size;
+       p->geometry->width = extended_area;
 
        /* Bottom */
-       add_scene_rect(part_list, LAB_SSD_PART_CORNER_BOTTOM_LEFT, parent,
-               corner_size, corner_size,
-               0, corner_size + side_height, invisible);
-       add_scene_rect(part_list, LAB_SSD_PART_BOTTOM, parent,
-               side_width, extended_area,
-               corner_size, extended_area + full_height, invisible);
-       add_scene_rect(part_list, LAB_SSD_PART_CORNER_BOTTOM_RIGHT, parent,
-               corner_size, corner_size,
-               corner_size + side_width, corner_size + side_height, invisible);
+       p = add_extent(part_list, LAB_SSD_PART_CORNER_BOTTOM_LEFT, parent);
+       p->geometry->width = corner_size;
+       p->geometry->height = corner_size;
+
+       p = add_extent(part_list, LAB_SSD_PART_BOTTOM, parent);
+       p->geometry->x = corner_size;
+       p->geometry->height = extended_area;
+
+       p = add_extent(part_list, LAB_SSD_PART_CORNER_BOTTOM_RIGHT, parent);
+       p->geometry->width = corner_size;
+       p->geometry->height = corner_size;
 }
 
 void
@@ -71,6 +99,10 @@ ssd_extents_update(struct view *view)
                wlr_scene_node_set_enabled(&view->ssd.extents.tree->node, true);
        }
 
+       if (!view->output) {
+               return;
+       }
+
        struct theme *theme = view->server->theme;
 
        int width = view->w;
@@ -82,42 +114,87 @@ ssd_extents_update(struct view *view)
        int side_width = full_width + extended_area * 2 - corner_size * 2;
        int side_height = full_height + extended_area * 2 - corner_size * 2;
 
+       struct wlr_box part_box;
+       struct wlr_box result_box;
        struct ssd_part *part;
        struct wlr_scene_rect *rect;
+
+       /* Convert usable area into layout coordinates */
+       struct wlr_box usable_area;
+       memcpy(&usable_area, &view->output->usable_area, sizeof(struct wlr_box));
+       lab_wlr_output_layout_layout_coords(view->server->output_layout,
+               view->output->wlr_output, &usable_area.x, &usable_area.y);
+
+       /* Remember base layout coordinates */
+       int base_x, base_y;
+       wlr_scene_node_coords(&view->ssd.extents.tree->node, &base_x, &base_y);
+
+       struct wlr_box *target;
        wl_list_for_each(part, &view->ssd.extents.parts, link) {
                rect = lab_wlr_scene_get_rect(part->node);
+               target = part->geometry;
                switch (part->type) {
                case LAB_SSD_PART_TOP:
-                       wlr_scene_rect_set_size(rect, side_width, extended_area);
-                       continue;
+                       target->width = side_width;
+                       break;
                case LAB_SSD_PART_CORNER_TOP_RIGHT:
-                       wlr_scene_node_set_position(
-                               part->node, corner_size + side_width, 0);
-                       continue;
+                       target->x = corner_size + side_width;
+                       break;
                case LAB_SSD_PART_LEFT:
-                       wlr_scene_rect_set_size(rect, extended_area, side_height);
-                       continue;
+                       target->height = side_height;
+                       break;
                case LAB_SSD_PART_RIGHT:
-                       wlr_scene_rect_set_size(rect, extended_area, side_height);
-                       wlr_scene_node_set_position(
-                               part->node, extended_area + full_width, corner_size);
-                       continue;
+                       target->x = extended_area + full_width;
+                       target->height = side_height;
+                       break;
                case LAB_SSD_PART_CORNER_BOTTOM_LEFT:
-                       wlr_scene_node_set_position(
-                               part->node, 0, corner_size + side_height);
-                       continue;
+                       target->y = corner_size + side_height;
+                       break;
                case LAB_SSD_PART_BOTTOM:
-                       wlr_scene_rect_set_size(rect, side_width, extended_area);
-                       wlr_scene_node_set_position(
-                               part->node, corner_size, extended_area + full_height);
-                       continue;
+                       target->width = side_width;
+                       target->y = extended_area + full_height;
+                       break;
                case LAB_SSD_PART_CORNER_BOTTOM_RIGHT:
-                       wlr_scene_node_set_position(part->node,
-                               corner_size + side_width, corner_size + side_height);
-                       continue;
+                       target->x = corner_size + side_width;
+                       target->y = corner_size + side_height;
+                       break;
                default:
+                       break;
+               }
+
+               /* Get layout geometry of what the part *should* be */
+               part_box.x = base_x + target->x;
+               part_box.y = base_y + target->y;
+               part_box.width = target->width;
+               part_box.height = target->height;
+
+               /* Constrain part to output->usable_area */
+               if (!wlr_box_intersection(&result_box, &part_box, &usable_area)) {
+                       /* Not visible */
+                       wlr_scene_node_set_enabled(part->node, false);
+                       continue;
+               } else if (!part->node->state.enabled) {
+                       wlr_scene_node_set_enabled(part->node, true);
+               }
+
+               if (part_box.width != result_box.width
+                               || part_box.height != result_box.height) {
+                       /* Partly visible */
+                       wlr_scene_rect_set_size(rect, result_box.width, result_box.height);
+                       wlr_scene_node_set_position(part->node,
+                               target->x + (result_box.x - part_box.x),
+                               target->y + (result_box.y - part_box.y));
                        continue;
                }
+
+               /* Fully visible */
+               if (target->x != part->node->state.x
+                               || target->y != part->node->state.y) {
+                       wlr_scene_node_set_position(part->node, target->x, target->y);
+               }
+               if (target->width != rect->width || target->height != rect->height) {
+                       wlr_scene_rect_set_size(rect, target->width, target->height);
+               }
        }
 }
 
index 95eac508f5cad5837b09f2f5577595cb77364554..ec754697983d0e5236853b266f45600f84ec2bd7 100644 (file)
@@ -66,8 +66,8 @@ finish_scene_button(struct wl_list *part_list, enum ssd_part_type type,
 
        /* Hover overlay */
        struct ssd_part *hover_part;
-       hover_part = add_scene_rect(part_list, type, parent,
-               BUTTON_WIDTH, rc.theme->title_height, offset_x, offset_y, hover_bg);
+       hover_part = add_scene_rect(part_list, type, parent, BUTTON_WIDTH,
+               rc.theme->title_height, offset_x, offset_y, hover_bg);
        wlr_scene_node_set_enabled(hover_part->node, false);
 }
 
@@ -77,7 +77,10 @@ add_scene_button_corner(struct wl_list *part_list, enum ssd_part_type type,
        struct wlr_buffer *icon_buffer, int x)
 {
        struct ssd_part *part;
-       /* Background, y adjusted for border_width */
+       /*
+        * Background, y adjusted for border_width which is
+        * already included in rendered theme.c / corner_buffer
+        */
        part = add_scene_buffer(part_list, type, parent, corner_buffer,
                x, -rc.theme->border_width);
        finish_scene_button(part_list, type, part->node, icon_buffer);
@@ -116,9 +119,15 @@ ssd_destroy_parts(struct wl_list *list)
        wl_list_for_each_reverse_safe(part, tmp, list, link) {
                if (part->node) {
                        wlr_scene_node_destroy(part->node);
+                       part->node = NULL;
                }
                if (part->buffer) {
                        wlr_buffer_drop(&part->buffer->base);
+                       part->buffer = NULL;
+               }
+               if (part->geometry) {
+                       free(part->geometry);
+                       part->geometry = NULL;
                }
                wl_list_remove(&part->link);
                free(part);
index 4d661e041ada8b20686bc87f973875f2da2dc97d..91c9aadc33e05b87888a3e214c5cd3c61885ca47 100644 (file)
@@ -35,6 +35,7 @@ view_move(struct view *view, double x, double y)
        }
        view_discover_output(view);
        wlr_scene_node_set_position(&view->scene_tree->node, view->x, view->y);
+       ssd_update_geometry(view);
 }
 
 /* N.B. Use view_move() if not resizing. */