]> git.mdlowis.com Git - proto/labwc.git/commitdiff
view: minimize parents/children together
authorJohan Malm <jgm323@gmail.com>
Wed, 2 Aug 2023 19:57:39 +0000 (20:57 +0100)
committerJohan Malm <johanmalm@users.noreply.github.com>
Sat, 5 Aug 2023 14:25:00 +0000 (15:25 +0100)
Minimize the whole view-hierarchy from top to bottom regardless of which
one in the hierarchy requested the minimize. For example, if an 'About' or
'Open File' dialog is minimized, its toplevel is minimized also, and vice
versa.

For reference:
- This is consistent with in openbox, where child views (dialogs) can be
  minimized, but when doing so the parent is also minimized.
- In mutter these types of dialogs cannot be minimized (via client-menu or
  otherwise).
- In both openbox and mutter, when a toplevel window is minimized any open
  children are also minimized.

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

index 6076d67255809bdf4efb31db81f56694faa8acfb..79963b4b8b484a67d5d5762399719d57933fa18f 100644 (file)
@@ -55,6 +55,8 @@ struct view_impl {
        void (*minimize)(struct view *view, bool minimize);
        void (*move_to_front)(struct view *view);
        void (*move_to_back)(struct view *view);
+       struct view *(*get_root)(struct view *self);
+       void (*append_children)(struct view *self, struct wl_array *children);
 };
 
 struct view {
@@ -212,6 +214,8 @@ void view_snap_to_region(struct view *view, struct region *region, bool store_na
 
 void view_move_to_front(struct view *view);
 void view_move_to_back(struct view *view);
+struct view *view_get_root(struct view *view);
+void view_append_children(struct view *view, struct wl_array *children);
 
 const char *view_get_string_prop(struct view *view, const char *prop);
 void view_update_title(struct view *view);
index 8b1f5743432781ab409569e777c9470756e03053..4c72e13f5f02907b6c06a91775a7ada67977cf15 100644 (file)
@@ -238,8 +238,8 @@ view_adjust_size(struct view *view, int *w, int *h)
        *h = MAX(*h, LAB_MIN_VIEW_HEIGHT);
 }
 
-void
-view_minimize(struct view *view, bool minimized)
+static void
+_minimize(struct view *view, bool minimized)
 {
        assert(view);
        if (view->minimized == minimized) {
@@ -272,6 +272,40 @@ view_minimize(struct view *view, bool minimized)
        }
 }
 
+static void
+minimize_sub_views(struct view *view, bool minimized)
+{
+       struct view **child;
+       struct wl_array children;
+
+       wl_array_init(&children);
+       view_append_children(view, &children);
+       wl_array_for_each(child, &children) {
+               _minimize(*child, minimized);
+               minimize_sub_views(*child, minimized);
+       }
+       wl_array_release(&children);
+}
+
+/*
+ * Minimize the whole view-hierarchy from top to bottom regardless of which one
+ * in the hierarchy requested the minimize. For example, if an 'About' or
+ * 'Open File' dialog is minimized, its toplevel is minimized also. And vice
+ * versa.
+ */
+void
+view_minimize(struct view *view, bool minimized)
+{
+       /*
+        * Minimize the root window first because some xwayland clients send a
+        * request-unmap to sub-windows at this point (for example gimp and its
+        * 'open file' dialog), so it saves trying to unmap them twice
+        */
+       struct view *root = view_get_root(view);
+       _minimize(root, minimized);
+       minimize_sub_views(root, minimized);
+}
+
 static bool
 view_compute_centered_position(struct view *view, const struct wlr_box *ref,
                int w, int h, int *x, int *y)
@@ -1042,6 +1076,25 @@ view_move_to_back(struct view *view)
        }
 }
 
+struct view *
+view_get_root(struct view *view)
+{
+       assert(view);
+       if (view->impl->get_root) {
+               return view->impl->get_root(view);
+       }
+       return view;
+}
+
+void
+view_append_children(struct view *view, struct wl_array *children)
+{
+       assert(view);
+       if (view->impl->append_children) {
+               view->impl->append_children(view, children);
+       }
+}
+
 const char *
 view_get_string_prop(struct view *view, const char *prop)
 {
index c54796c56c8a004360666ae1d8974372ec248613..7e557f509681eb03c97c1d8ebdb05b3d7d12ab6e 100644 (file)
--- a/src/xdg.c
+++ b/src/xdg.c
@@ -335,6 +335,10 @@ enum z_direction {
        LAB_TO_BACK,
 };
 
+/*
+ * TODO: Combine append_children() and move_sub_views() as much as possible.
+ * https://github.com/labwc/labwc/pull/998#discussion_r1284085575
+ */
 static void
 move_sub_views(struct view *parent, enum z_direction z_direction)
 {
@@ -371,7 +375,7 @@ move_sub_views(struct view *parent, enum z_direction z_direction)
 
 /* Return the most senior parent (=root) view */
 static struct view *
-root_view_of_view(struct view *view)
+xdg_toplevel_view_get_root(struct view *view)
 {
        struct wlr_xdg_toplevel *root = top_parent_of(view);
        struct wlr_xdg_surface *surface = (struct wlr_xdg_surface *)root->base;
@@ -387,7 +391,7 @@ root_view_of_view(struct view *view)
 static void
 xdg_toplevel_view_move_to_front(struct view *view)
 {
-       struct view *root = root_view_of_view(view);
+       struct view *root = xdg_toplevel_view_get_root(view);
        view_impl_move_to_front(root);
        move_sub_views(root, LAB_TO_FRONT);
 }
@@ -395,11 +399,36 @@ xdg_toplevel_view_move_to_front(struct view *view)
 static void
 xdg_toplevel_view_move_to_back(struct view *view)
 {
-       struct view *root = root_view_of_view(view);
+       struct view *root = xdg_toplevel_view_get_root(view);
        view_impl_move_to_back(root);
        move_sub_views(root, LAB_TO_BACK);
 }
 
+static void
+xdg_toplevel_view_append_children(struct view *self, struct wl_array *children)
+{
+       struct wlr_xdg_toplevel *toplevel = xdg_toplevel_from_view(self);
+       struct view *view;
+
+       wl_list_for_each_reverse(view, &self->server->views, link)
+       {
+               if (view == self) {
+                       continue;
+               }
+               if (view->type != LAB_XDG_SHELL_VIEW) {
+                       continue;
+               }
+               if (!view->mapped && !view->minimized) {
+                       continue;
+               }
+               if (top_parent_of(view) != toplevel) {
+                       continue;
+               }
+               struct view **child = wl_array_add(children, sizeof(*child));
+               *child = view;
+       }
+}
+
 static void
 xdg_toplevel_view_set_activated(struct view *view, bool activated)
 {
@@ -554,6 +583,8 @@ static const struct view_impl xdg_toplevel_view_impl = {
        .minimize = xdg_toplevel_view_minimize,
        .move_to_front = xdg_toplevel_view_move_to_front,
        .move_to_back = xdg_toplevel_view_move_to_back,
+       .get_root = xdg_toplevel_view_get_root,
+       .append_children = xdg_toplevel_view_append_children,
 };
 
 void
index 46e411b66c57de0f1d1360d61e0c237fd7a892e0..7aef57626cab2ea77cbef6ae96d912e5379cea59 100644 (file)
@@ -527,6 +527,10 @@ enum z_direction {
        LAB_TO_BACK,
 };
 
+/*
+ * TODO: Combine append_children() and move_sub_views() as much as possible.
+ * https://github.com/labwc/labwc/pull/998#discussion_r1284085575
+ */
 static void
 move_sub_views(struct view *parent, enum z_direction z_direction)
 {
@@ -563,7 +567,7 @@ move_sub_views(struct view *parent, enum z_direction z_direction)
 }
 
 static struct view *
-root_view_of_view(struct view *view)
+xwayland_view_get_root(struct view *view)
 {
        struct wlr_xwayland_surface *root = top_parent_of(view);
        return (struct view *)root->data;
@@ -572,7 +576,7 @@ root_view_of_view(struct view *view)
 static void
 xwayland_view_move_to_front(struct view *view)
 {
-       struct view *root = root_view_of_view(view);
+       struct view *root = xwayland_view_get_root(view);
        view_impl_move_to_front(root);
        move_sub_views(root, LAB_TO_FRONT);
 }
@@ -580,11 +584,43 @@ xwayland_view_move_to_front(struct view *view)
 static void
 xwayland_view_move_to_back(struct view *view)
 {
-       struct view *root = root_view_of_view(view);
+       struct view *root = xwayland_view_get_root(view);
        view_impl_move_to_back(root);
        move_sub_views(root, LAB_TO_BACK);
 }
 
+static void
+xwayland_view_append_children(struct view *self, struct wl_array *children)
+{
+       struct wlr_xwayland_surface *surface = xwayland_surface_from_view(self);
+       struct view *view;
+
+       wl_list_for_each_reverse(view, &self->server->views, link)
+       {
+               if (view == self) {
+                       continue;
+               }
+               if (view->type != LAB_XWAYLAND_VIEW) {
+                       continue;
+               }
+               /*
+                * This happens when a view has never been mapped or when a
+                * client has requested a `handle_unmap`.
+                */
+               if (!view->surface) {
+                       continue;
+               }
+               if (!view->mapped && !view->minimized) {
+                       continue;
+               }
+               if (top_parent_of(view) != surface) {
+                       continue;
+               }
+               struct view **child = wl_array_add(children, sizeof(*child));
+               *child = view;
+       }
+}
+
 static void
 xwayland_view_set_activated(struct view *view, bool activated)
 {
@@ -628,6 +664,8 @@ static const struct view_impl xwayland_view_impl = {
        .minimize = xwayland_view_minimize,
        .move_to_front = xwayland_view_move_to_front,
        .move_to_back = xwayland_view_move_to_back,
+       .get_root = xwayland_view_get_root,
+       .append_children = xwayland_view_append_children,
 };
 
 void