]> git.mdlowis.com Git - proto/labwc.git/commitdiff
layer: support popups
authorJohan Malm <jgm323@gmail.com>
Sat, 26 Feb 2022 21:15:52 +0000 (21:15 +0000)
committerJohan Malm <jgm323@gmail.com>
Sat, 26 Feb 2022 22:36:16 +0000 (22:36 +0000)
include/layers.h
src/layers.c

index da88aafefc91368cdf73de376328b4364c9bf741..5db03c1f0595fa00d9d3f2b0e060e7042a2c429e 100644 (file)
@@ -8,13 +8,8 @@ struct server;
 
 #define LAB_NR_LAYERS (4)
 
-enum layer_parent {
-       LAYER_PARENT_LAYER,
-       LAYER_PARENT_POPUP,
-};
-
 struct lab_layer_surface {
-       struct wl_list link; /* output::layers[] */
+       struct wl_list link; /* output::layers */
        struct wlr_scene_layer_surface_v1 *scene_layer_surface;
 
        struct wl_listener destroy;
@@ -23,37 +18,19 @@ struct lab_layer_surface {
        struct wl_listener surface_commit;
        struct wl_listener output_destroy;
        struct wl_listener new_popup;
-       struct wl_listener new_subsurface;
 
        struct wlr_box geo;
        bool mapped;
-       /* TODO: add extent and layer */
+       /* TODO: add extent? */
        struct server *server;
 };
 
-/* FIXME: do we still need lab_layer_popup and lab_layer_subsurface? */
 struct lab_layer_popup {
        struct wlr_xdg_popup *wlr_popup;
-       enum layer_parent parent_type;
-       union {
-               struct lab_layer_surface *parent_layer;
-               struct lab_layer_popup *parent_popup;
-       };
-       struct wl_listener map;
-       struct wl_listener unmap;
-       struct wl_listener destroy;
-       struct wl_listener commit;
-       struct wl_listener new_popup;
-};
-
-struct lab_layer_subsurface {
-       struct wlr_subsurface *wlr_subsurface;
-       struct lab_layer_surface *layer_surface;
+       struct wlr_scene_node *scene_node;
 
-       struct wl_listener map;
-       struct wl_listener unmap;
        struct wl_listener destroy;
-       struct wl_listener commit;
+       struct wl_listener new_popup;
 };
 
 void layers_init(struct server *server);
index 901a72ecff3dbfdf4ce38132fd27328cab1e2091..3207e4b32edca5f3b07e257b648760373ab9e359 100644 (file)
@@ -2,7 +2,7 @@
 /*
  * layers.c - layer-shell implementation
  *
- * Based on:
+ * Based on
  *  - https://git.sr.ht/~sircmpwm/wio
  *  - https://github.com/swaywm/sway
  * Copyright (C) 2019 Drew DeVault and Sway developers
 #include <wlr/util/log.h>
 #include "layers.h"
 #include "labwc.h"
+#include "node-descriptor.h"
 
 void
 arrange_layers(struct output *output)
 {
-       struct server *server = output->server;
-       struct wlr_scene_output *scene_output =
-               wlr_scene_get_scene_output(server->scene, output->wlr_output);
-
        struct wlr_box full_area = { 0 };
        wlr_output_effective_resolution(output->wlr_output,
-                       &full_area.width, &full_area.height);
+               &full_area.width, &full_area.height);
        struct wlr_box usable_area = full_area;
 
        for (int i = 0; i < LAB_NR_LAYERS; i++) {
@@ -110,7 +107,6 @@ unmap(struct lab_layer_surface *layer)
        if (seat->focused_layer == layer->scene_layer_surface->layer_surface) {
                seat_set_focus_layer(seat, NULL);
        }
-       damage_all_outputs(layer->server);
 }
 
 static void
@@ -122,15 +118,15 @@ destroy_notify(struct wl_listener *listener, void *data)
                unmap(layer);
        }
 
-       /* TODO: sort this out properly */
        wl_list_remove(&layer->link);
        wl_list_remove(&layer->destroy.link);
        wl_list_remove(&layer->map.link);
+       wl_list_remove(&layer->unmap.link);
        wl_list_remove(&layer->surface_commit.link);
        if (layer->scene_layer_surface->layer_surface->output) {
                wl_list_remove(&layer->output_destroy.link);
-               struct output *output = output_from_wlr_output(
-                       layer->server, layer->scene_layer_surface->layer_surface->output);
+               struct output *output = output_from_wlr_output(layer->server,
+                       layer->scene_layer_surface->layer_surface->output);
                arrange_layers(output);
        }
        free(layer);
@@ -139,160 +135,128 @@ destroy_notify(struct wl_listener *listener, void *data)
 static void
 unmap_notify(struct wl_listener *listener, void *data)
 {
-       struct lab_layer_surface *l = wl_container_of(listener, l, unmap);
-       unmap(l);
+       return;
+       struct lab_layer_surface *lab_layer_surface =
+               wl_container_of(listener, lab_layer_surface, unmap);
+       unmap(lab_layer_surface);
 }
 
 static void
 map_notify(struct wl_listener *listener, void *data)
 {
-       struct wlr_layer_surface_v1 *l = data;
-       wlr_surface_send_enter(l->surface, l->output);
+       return;
+       struct wlr_layer_surface_v1 *layer_surface = data;
+       wlr_surface_send_enter(layer_surface->surface, layer_surface->output);
+}
+
+static struct
+lab_layer_surface *popup_get_layer(struct lab_layer_popup *popup)
+{
+       struct wlr_scene_node *node = popup->scene_node;
+       while (node) {
+               if (node->data) {
+                       struct node_descriptor *desc = node->data;
+                       if (desc->type == LAB_NODE_DESC_LAYER_SURFACE) {
+                               return desc->data;
+                       }
+               }
+               node = node->parent;
+       }
+       return NULL;
+}
+
+static void
+popup_handle_destroy(struct wl_listener *listener, void *data)
+{
+       struct lab_layer_popup *popup =
+               wl_container_of(listener, popup, destroy);
+       wl_list_remove(&popup->destroy.link);
+       wl_list_remove(&popup->new_popup.link);
+       free(popup);
 }
 
-//static struct
-//lab_layer_surface *popup_get_layer(struct lab_layer_popup *popup)
-//{
-//     while (popup->parent_type == LAYER_PARENT_POPUP) {
-//             popup = popup->parent_popup;
-//     }
-//     return popup->parent_layer;
-//}
-//
-//static void
-//popup_damage(struct lab_layer_popup *layer_popup, bool whole)
-//{
-//     struct lab_layer_surface *layer;
-//     while (true) {
-//             if (layer_popup->parent_type == LAYER_PARENT_POPUP) {
-//                     layer_popup = layer_popup->parent_popup;
-//             } else {
-//                     layer = layer_popup->parent_layer;
-//                     break;
-//             }
-//     }
-//     damage_all_outputs(layer->server);
-//}
-//
-//static void
-//popup_handle_map(struct wl_listener *listener, void *data)
-//{
-//     struct lab_layer_popup *popup = wl_container_of(listener, popup, map);
-//     struct lab_layer_surface *layer = popup_get_layer(popup);
-//     struct wlr_output *wlr_output = layer->scene_layer_surface->layer_surface->output;
-//     wlr_surface_send_enter(popup->wlr_popup->base->surface, wlr_output);
-//     popup_damage(popup, true);
-//}
-//
-//static void
-//popup_handle_unmap(struct wl_listener *listener, void *data)
-//{
-//     struct lab_layer_popup *popup = wl_container_of(listener, popup, unmap);
-//     popup_damage(popup, true);
-//}
-//
-//static void
-//popup_handle_commit(struct wl_listener *listener, void *data)
-//{
-//     struct lab_layer_popup *popup = wl_container_of(listener, popup, commit);
-//     popup_damage(popup, false);
-//}
-//
-//static void
-//popup_handle_destroy(struct wl_listener *listener, void *data)
-//{
-//     struct lab_layer_popup *popup =
-//             wl_container_of(listener, popup, destroy);
-//     wl_list_remove(&popup->destroy.link);
-//     free(popup);
-//}
-//
-//static void
-//popup_unconstrain(struct lab_layer_popup *popup)
-//{
-//     struct lab_layer_surface *layer = popup_get_layer(popup);
-//     struct wlr_xdg_popup *wlr_popup = popup->wlr_popup;
-//     struct output *output = layer->scene_layer_surface->layer_surface->output->data;
-//
-//     struct wlr_box output_box = { 0 };
-//     wlr_output_effective_resolution(output->wlr_output, &output_box.width,
-//             &output_box.height);
-//
-//     struct wlr_box output_toplevel_sx_box = {
-//             .x = -layer->geo.x,
-//             .y = -layer->geo.y,
-//             .width = output_box.width,
-//             .height = output_box.height,
-//     };
-//
-//     wlr_xdg_popup_unconstrain_from_box(wlr_popup, &output_toplevel_sx_box);
-//}
-//
-//static void popup_handle_new_popup(struct wl_listener *listener, void *data);
-//
-//static struct lab_layer_popup *
-//create_popup(struct wlr_xdg_popup *wlr_popup,
-//             enum layer_parent parent_type, void *parent)
-//{
-//     struct lab_layer_popup *popup =
-//             calloc(1, sizeof(struct lab_layer_popup));
-//     if (!popup) {
-//             return NULL;
-//     }
-//
-//     struct lab_layer_surface *layer = parent_type == LAYER_PARENT_LAYER
-//                     ? (struct lab_layer_surface *)parent
-//                     : (struct lab_layer_popup *)parent;
-//     struct server *server = layer->server;
-//
-//     popup->wlr_popup = wlr_popup;
-//     popup->parent_type = parent_type;
-//     popup->parent_layer = parent;
-//
-//     popup->destroy.notify = popup_handle_destroy;
-//     wl_signal_add(&wlr_popup->base->events.destroy, &popup->destroy);
-//     popup->new_popup.notify = popup_handle_new_popup;
-//     wl_signal_add(&wlr_popup->base->events.new_popup, &popup->new_popup);
-//
-//     if (!wlr_surface_is_layer_surface(wlr_popup->base->surface)) {
-//             wlr_log(WLR_ERROR, "xdg_surface is not layer surface");
-//             return;
-//     }
-//
-//     struct wlr_output *wlr_output =
-//             layer->scene_layer_surface->layer_surface->data;
-//     struct output *output = output_from_wlr_output(server, wlr_output);
-//
-//     struct wlr_scene_tree *selected_layer =
-//             output->layer_tree[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY];
-//     struct wlr_scene_node *node =
-//             wlr_scene_layer_surface_v1_create(&server->view_tree->node,
-//                     wlr_popup->base->surface->data);
-//     wlr_popup->base->surface->data =
-//             wlr_scene_xdg_surface_create(&selected_layer->node, wlr_popup->base);
-//
-//     popup_unconstrain(popup);
-//
-//     return popup;
-//}
-//
-//static void
-//popup_handle_new_popup(struct wl_listener *listener, void *data)
-//{
-//     struct lab_layer_popup *lab_layer_popup =
-//             wl_container_of(listener, lab_layer_popup, new_popup);
-//     struct wlr_xdg_popup *wlr_popup = data;
-//     create_popup(wlr_popup, LAYER_PARENT_POPUP, lab_layer_popup);
-//}
-//
-//static void
-//new_popup_notify(struct wl_listener *listener, void *data)
-//{
-//     struct lab_layer_surface *lab_layer_surface =
-//             wl_container_of(listener, lab_layer_surface, new_popup);
-//     struct wlr_xdg_popup *wlr_popup = data;
-//     create_popup(wlr_popup, LAYER_PARENT_LAYER, lab_layer_surface);
-//}
+static void
+popup_unconstrain(struct lab_layer_popup *popup)
+{
+       struct lab_layer_surface *layer = popup_get_layer(popup);
+       if (!layer) {
+               return;
+       }
+       struct wlr_xdg_popup *wlr_popup = popup->wlr_popup;
+       struct output *output =
+               layer->scene_layer_surface->layer_surface->output->data;
+
+       struct wlr_box output_box = { 0 };
+       wlr_output_effective_resolution(output->wlr_output, &output_box.width,
+               &output_box.height);
+
+       /*
+        * Output geometry expressed in the coordinate system of the toplevel
+        * parent of popup
+        */
+       struct wlr_box output_toplevel_sx_box = {
+               .x = -layer->geo.x,
+               .y = -layer->geo.y,
+               .width = output_box.width,
+               .height = output_box.height,
+       };
+
+       wlr_xdg_popup_unconstrain_from_box(wlr_popup, &output_toplevel_sx_box);
+}
+
+static void popup_handle_new_popup(struct wl_listener *listener, void *data);
+
+static struct lab_layer_popup *
+create_popup(struct wlr_xdg_popup *wlr_popup, struct wlr_scene_node *parent)
+{
+       struct lab_layer_popup *popup =
+               calloc(1, sizeof(struct lab_layer_popup));
+       if (!popup) {
+               return NULL;
+       }
+
+       popup->wlr_popup = wlr_popup;
+       popup->scene_node =
+               wlr_scene_xdg_surface_create(parent, wlr_popup->base);
+       if (!popup->scene_node) {
+               free(popup);
+               return NULL;
+       }
+       node_descriptor_create(popup->scene_node,
+               LAB_NODE_DESC_LAYER_POPUP, popup);
+
+       popup->destroy.notify = popup_handle_destroy;
+       wl_signal_add(&wlr_popup->base->events.destroy, &popup->destroy);
+       popup->new_popup.notify = popup_handle_new_popup;
+       wl_signal_add(&wlr_popup->base->events.new_popup, &popup->new_popup);
+
+       /*
+        * FIXME: should we put popups in ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY
+        * or a dedicated output->layer_popup_tree - so that for example
+        * a panel in the bottom layer displays any popup above views.
+        */
+
+       popup_unconstrain(popup);
+       return popup;
+}
+
+static void
+popup_handle_new_popup(struct wl_listener *listener, void *data)
+{
+       struct lab_layer_popup *lab_layer_popup =
+               wl_container_of(listener, lab_layer_popup, new_popup);
+       struct wlr_xdg_popup *wlr_popup = data;
+       create_popup(wlr_popup, lab_layer_popup->scene_node);
+}
+
+static void
+new_popup_notify(struct wl_listener *listener, void *data)
+{
+       struct lab_layer_surface *lab_layer_surface =
+               wl_container_of(listener, lab_layer_surface, new_popup);
+       struct wlr_xdg_popup *wlr_popup = data;
+       create_popup(wlr_popup, lab_layer_surface->scene_layer_surface->node);
+}
 
 static void
 new_layer_surface_notify(struct wl_listener *listener, void *data)
@@ -327,13 +291,8 @@ new_layer_surface_notify(struct wl_listener *listener, void *data)
        surface->unmap.notify = unmap_notify;
        wl_signal_add(&layer_surface->events.unmap, &surface->unmap);
 
-       /* TODO: support popups */
-//     surface->new_popup.notify = new_popup_notify;
-//     wl_signal_add(&layer_surface->events.new_popup, &surface->new_popup);
-//
-//     surface->new_subsurface.notify = new_subsurface_notify;
-//     wl_signal_add(&layer_surface->surface->events.new_subsurface,
-//             &surface->new_subsurface);
+       surface->new_popup.notify = new_popup_notify;
+       wl_signal_add(&layer_surface->events.new_popup, &surface->new_popup);
 
        struct output *output = layer_surface->output->data;
 
@@ -342,12 +301,14 @@ new_layer_surface_notify(struct wl_listener *listener, void *data)
 
        surface->scene_layer_surface = wlr_scene_layer_surface_v1_create(
                &selected_layer->node, layer_surface);
+       node_descriptor_create(surface->scene_layer_surface->node,
+               LAB_NODE_DESC_LAYER_SURFACE, surface);
 
        surface->server = server;
        surface->scene_layer_surface->layer_surface = layer_surface;
 
-       /* wlr_surface->data needed to find parent in xdg_surface_new() */
-       layer_surface->surface->data = surface->scene_layer_surface->node;
+//     /* wlr_surface->data needed to find parent in xdg_surface_new() */
+//     layer_surface->surface->data = surface->scene_layer_surface->node;
 
        surface->output_destroy.notify = output_destroy_notify;
        wl_signal_add(&layer_surface->output->events.destroy,