]> git.mdlowis.com Git - proto/labwc.git/commitdiff
view: ensure that floating views don't overlap top panels
authorJohn Lindgren <john@jlindgren.net>
Fri, 3 Nov 2023 16:38:07 +0000 (12:38 -0400)
committerJohan Malm <johanmalm@users.noreply.github.com>
Sun, 5 Nov 2023 15:03:13 +0000 (15:03 +0000)
The top_left_edge_boundary_check() function in xwayland.c ensures that
views trying to position themselves at 0,0 don't end up with a titlebar
offscreen. However, it doesn't take into account the usable area and
thus these views can still end up overlapping a top panel.

Also, there is no good reason for top_left_edge_boundary_check() to be
xwayland-specific. This logic should really be part of
view_adjust_for_layout_change().

To fix all this, add a new view_adjust_floating_geometry() function,
which replaces the existing similar (and duplicated) logic in
view_apply_natural_geometry() and view_adjust_for_layout_change().

view_adjust_for_layout_change() is already being called from xwayland's
set_initial_position(), so top_left_edge_boundary_check() is now
redundant and can just be deleted.

Lightly tested with waybar and feh --geometry 640x480+0+0. The feh
window is now correctly positioned below waybar, even if started before
waybar (in that case, the feh window is moved when waybar starts).

include/view.h
src/view.c
src/xwayland.c

index da6299d1ad1cda474505c99b776f00b341a19008..c8640485430551a1d0b5bc1b49c7d8d9aff1bb19 100644 (file)
@@ -356,6 +356,7 @@ void view_moved(struct view *view);
 void view_minimize(struct view *view, bool minimized);
 bool view_compute_centered_position(struct view *view,
        const struct wlr_box *ref, int w, int h, int *x, int *y);
+bool view_adjust_floating_geometry(struct view *view, struct wlr_box *geometry);
 void view_store_natural_geometry(struct view *view);
 
 /**
index 73f699f0a904fddccd5f1796e1e4ad61a72d4273..b440fb6f64266f28c6aa7894436b5666ba10f3cd 100644 (file)
@@ -542,6 +542,7 @@ bool
 view_compute_centered_position(struct view *view, const struct wlr_box *ref,
                int w, int h, int *x, int *y)
 {
+       assert(view);
        if (w <= 0 || h <= 0) {
                wlr_log(WLR_ERROR, "view has empty geometry, not centering");
                return false;
@@ -577,6 +578,47 @@ view_compute_centered_position(struct view *view, const struct wlr_box *ref,
        return true;
 }
 
+bool
+view_adjust_floating_geometry(struct view *view, struct wlr_box *geometry)
+{
+       assert(view);
+       if (!output_is_usable(view->output)) {
+               wlr_log(WLR_ERROR, "view has no output, not positioning");
+               return false;
+       }
+
+       bool adjusted = false;
+       /*
+        * First check whether the view is onscreen. For now, "onscreen"
+        * is defined as even one pixel of the client area being visible.
+        */
+       if (wlr_output_layout_intersects(view->server->output_layout,
+                       NULL, geometry)) {
+               /*
+                * If onscreen, then make sure the titlebar is also
+                * visible (and not overlapping any panels/docks)
+                */
+               struct border margin = ssd_get_margin(view->ssd);
+               struct wlr_box usable =
+                       output_usable_area_in_layout_coords(view->output);
+
+               if (geometry->x < usable.x + margin.left) {
+                       geometry->x = usable.x + margin.left;
+                       adjusted = true;
+               }
+               if (geometry->y < usable.y + margin.top) {
+                       geometry->y = usable.y + margin.top;
+                       adjusted = true;
+               }
+       } else {
+               /* If offscreen, then just center the view */
+               adjusted = view_compute_centered_position(view, NULL,
+                       geometry->width, geometry->height,
+                       &geometry->x, &geometry->y);
+       }
+       return adjusted;
+}
+
 static void
 set_fallback_geometry(struct view *view)
 {
@@ -630,19 +672,9 @@ view_apply_natural_geometry(struct view *view)
        assert(view);
        assert(view_is_floating(view));
 
-       struct wlr_output_layout *layout = view->server->output_layout;
-       if (wlr_output_layout_intersects(layout, NULL, &view->natural_geometry)
-                       || wl_list_empty(&layout->outputs)) {
-               /* restore to original geometry */
-               view_move_resize(view, view->natural_geometry);
-       } else {
-               /* reposition if original geometry is offscreen */
-               struct wlr_box box = view->natural_geometry;
-               if (view_compute_centered_position(view, NULL, box.width,
-                               box.height, &box.x, &box.y)) {
-                       view_move_resize(view, box);
-               }
-       }
+       struct wlr_box geometry = view->natural_geometry;
+       view_adjust_floating_geometry(view, &geometry);
+       view_move_resize(view, geometry);
 }
 
 static void
@@ -1147,9 +1179,9 @@ view_adjust_for_layout_change(struct view *view)
                view_apply_natural_geometry(view);
        } else {
                /* reposition view if it's offscreen */
-               if (!wlr_output_layout_intersects(view->server->output_layout,
-                               NULL, &view->pending)) {
-                       view_center(view, NULL);
+               struct wlr_box geometry = view->pending;
+               if (view_adjust_floating_geometry(view, &geometry)) {
+                       view_move_resize(view, geometry);
                }
        }
        if (view->toplevel.handle) {
index 6e4fae7f58f809d8e16ef07186bd5adff8783c98..eee7eb6cc96e3dc3b2b29ea309d084b52b364e2e 100644 (file)
@@ -480,19 +480,6 @@ set_initial_position(struct view *view,
        }
 }
 
-static void
-top_left_edge_boundary_check(struct view *view)
-{
-       struct wlr_box deco = ssd_max_extents(view);
-       if (deco.x < 0) {
-               view->current.x -= deco.x;
-       }
-       if (deco.y < 0) {
-               view->current.y -= deco.y;
-       }
-       view->impl->configure(view, view->current);
-}
-
 static void
 init_foreign_toplevel(struct view *view)
 {
@@ -589,10 +576,6 @@ xwayland_view_map(struct view *view)
                view_moved(view);
        }
 
-       if (view->ssd_enabled && view_is_floating(view)) {
-               top_left_edge_boundary_check(view);
-       }
-
        /* Add commit here, as xwayland map/unmap can change the wlr_surface */
        wl_signal_add(&xwayland_surface->surface->events.commit, &view->commit);
        view->commit.notify = handle_commit;