commit 5936cf5aff5a2cf781c339b7ae0e245a18dda8a8
parent a22ca29561af5b1c9f6da39f2646d47727fb0757
Author: deurzen <max@deurzen.net>
Date: Wed, 1 Jun 2022 06:32:08 +0200
implements layer shell popup stacking
Diffstat:
5 files changed, 333 insertions(+), 16 deletions(-)
diff --git a/include/kranewl/scene-layer.hh b/include/kranewl/scene-layer.hh
@@ -10,5 +10,6 @@ enum SceneLayer : unsigned short {
SCENE_LAYER_FREE = 3,
SCENE_LAYER_TOP = 4,
SCENE_LAYER_OVERLAY = 5,
- SCENE_LAYER_NOFOCUS = 6,
+ SCENE_LAYER_POPUP = 6,
+ SCENE_LAYER_NOFOCUS = 7,
};
diff --git a/include/kranewl/server.hh b/include/kranewl/server.hh
@@ -65,7 +65,7 @@ public:
struct wlr_data_device_manager* mp_data_device_manager;
struct wlr_output_layout* mp_output_layout;
struct wlr_scene* mp_scene;
- std::array<struct wlr_scene_node*, 7> m_scene_layers;
+ std::array<struct wlr_scene_node*, 8> m_scene_layers;
Seat m_seat;
private:
diff --git a/include/kranewl/tree/layer.hh b/include/kranewl/tree/layer.hh
@@ -5,16 +5,18 @@
#include <kranewl/scene-layer.hh>
#include <kranewl/tree/node.hh>
-#include <chrono>
-
extern "C" {
#include <wayland-server-core.h>
}
+#include <chrono>
+#include <vector>
+
typedef class Server* Server_ptr;
typedef class Model* Model_ptr;
typedef class Seat* Seat_ptr;
typedef class Output* Output_ptr;
+typedef struct LayerPopup* LayerPopup_ptr;
typedef struct Layer final : public Node {
Layer(
@@ -35,6 +37,7 @@ typedef struct Layer final : public Node {
static void handle_map(struct wl_listener*, void*);
static void handle_unmap(struct wl_listener*, void*);
static void handle_surface_commit(struct wl_listener*, void*);
+ static void handle_new_popup(struct wl_listener*, void*);
static void handle_destroy(struct wl_listener*, void*);
bool mapped() const { return m_mapped; }
@@ -53,11 +56,14 @@ typedef struct Layer final : public Node {
SceneLayer m_scene_layer;
struct wlr_layer_surface_v1* mp_layer_surface;
+ std::vector<LayerPopup_ptr> m_popups;
+
pid_t m_pid;
struct wl_listener ml_map;
struct wl_listener ml_unmap;
struct wl_listener ml_surface_commit;
+ struct wl_listener ml_new_popup;
struct wl_listener ml_destroy;
private:
@@ -66,3 +72,56 @@ private:
std::chrono::time_point<std::chrono::steady_clock> m_managed_since;
}* Layer_ptr;
+
+typedef struct LayerPopup final {
+ LayerPopup(
+ struct wlr_xdg_popup*,
+ Layer_ptr,
+ Server_ptr,
+ Model_ptr,
+ Seat_ptr
+ );
+
+ LayerPopup(
+ struct wlr_xdg_popup*,
+ LayerPopup_ptr,
+ Layer_ptr,
+ Server_ptr,
+ Model_ptr,
+ Seat_ptr
+ );
+
+ ~LayerPopup();
+
+ Region const& region() { return m_region; }
+ void set_region(Region const&);
+
+ static void handle_map(struct wl_listener*, void*);
+ static void handle_unmap(struct wl_listener*, void*);
+ static void handle_surface_commit(struct wl_listener*, void*);
+ static void handle_new_popup(struct wl_listener*, void*);
+ static void handle_destroy(struct wl_listener*, void*);
+
+ Server_ptr mp_server;
+ Model_ptr mp_model;
+ Seat_ptr mp_seat;
+
+ Layer_ptr mp_root;
+ LayerPopup_ptr mp_parent;
+
+ struct wlr_scene_node* mp_scene;
+ SceneLayer m_scene_layer;
+ struct wlr_xdg_popup* mp_wlr_popup;
+
+ std::vector<LayerPopup_ptr> m_popups;
+
+ struct wl_listener ml_map;
+ struct wl_listener ml_unmap;
+ struct wl_listener ml_surface_commit;
+ struct wl_listener ml_new_popup;
+ struct wl_listener ml_destroy;
+
+private:
+ Region m_region;
+
+}* LayerPopup_ptr;
diff --git a/src/kranewl/server.cc b/src/kranewl/server.cc
@@ -110,6 +110,7 @@ Server::Server(Model_ptr model)
&wlr_scene_tree_create(&mp_scene->node)->node,
&wlr_scene_tree_create(&mp_scene->node)->node,
&wlr_scene_tree_create(&mp_scene->node)->node,
+ &wlr_scene_tree_create(&mp_scene->node)->node,
&wlr_scene_tree_create(&mp_scene->node)->node
},
m_seat([this]() {
diff --git a/src/kranewl/tree/layer.cc b/src/kranewl/tree/layer.cc
@@ -14,6 +14,7 @@ extern "C" {
#include <wlr/types/wlr_layer_shell_v1.h>
#include <wlr/types/wlr_scene.h>
#include <wlr/types/wlr_seat.h>
+#include <wlr/types/wlr_xdg_shell.h>
}
#undef static
#undef namespace
@@ -37,6 +38,7 @@ Layer::Layer(
ml_map({ .notify = Layer::handle_map }),
ml_unmap({ .notify = Layer::handle_unmap }),
ml_surface_commit({ .notify = Layer::handle_surface_commit }),
+ ml_new_popup({ .notify = Layer::handle_new_popup }),
ml_destroy({ .notify = Layer::handle_destroy }),
m_mapped(0),
m_managed_since(std::chrono::steady_clock::now())
@@ -44,6 +46,7 @@ Layer::Layer(
wl_signal_add(&mp_layer_surface->events.map, &ml_map);
wl_signal_add(&mp_layer_surface->events.unmap, &ml_unmap);
wl_signal_add(&mp_layer_surface->surface->events.commit, &ml_surface_commit);
+ wl_signal_add(&mp_layer_surface->events.new_popup, &ml_new_popup);
wl_signal_add(&mp_layer_surface->events.destroy, &ml_destroy);
}
@@ -97,10 +100,10 @@ Layer::handle_map(struct wl_listener* listener, void*)
layer->mp_model->register_layer(layer);
- struct wlr_layer_surface_v1_state initial_state = layer->mp_layer_surface->current;
- layer->mp_layer_surface->current = layer->mp_layer_surface->pending;
+ struct wlr_layer_surface_v1_state initial_state = layer->mp_layer_surface->current;
+ layer->mp_layer_surface->current = layer->mp_layer_surface->pending;
layer->mp_output->arrange_layers();
- layer->mp_layer_surface->current = initial_state;
+ layer->mp_layer_surface->current = initial_state;
wlr_surface_send_enter(
layer->mp_layer_surface->surface,
@@ -145,30 +148,29 @@ Layer::handle_surface_commit(struct wl_listener* listener, void*)
struct wlr_layer_surface_v1* layer_surface = layer->mp_layer_surface;
struct wlr_output* wlr_output = layer_surface->output;
- SceneLayer scene_layer;
switch (layer_surface->current.layer) {
case ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND:
- scene_layer = SCENE_LAYER_BACKGROUND;
+ layer->m_scene_layer = SCENE_LAYER_BACKGROUND;
break;
case ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM:
- scene_layer = SCENE_LAYER_BOTTOM;
+ layer->m_scene_layer = SCENE_LAYER_BOTTOM;
break;
case ZWLR_LAYER_SHELL_V1_LAYER_TOP:
- scene_layer = SCENE_LAYER_TOP;
+ layer->m_scene_layer = SCENE_LAYER_TOP;
break;
case ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY:
- scene_layer = SCENE_LAYER_OVERLAY;
+ layer->m_scene_layer = SCENE_LAYER_OVERLAY;
break;
default:
spdlog::error("No applicable scene layer found for layer surface");
spdlog::warn("Not committing surface");
- scene_layer = SCENE_LAYER_NONE;
+ layer->m_scene_layer = SCENE_LAYER_NONE;
return;
}
wlr_scene_node_reparent(
layer->mp_scene,
- layer->mp_server->m_scene_layers[scene_layer]
+ layer->mp_server->m_scene_layers[layer->m_scene_layer]
);
Output_ptr output;
@@ -180,12 +182,70 @@ Layer::handle_surface_commit(struct wl_listener* listener, void*)
layer->m_mapped = layer_surface->mapped;
- if (layer->mp_server->m_scene_layers[scene_layer] != layer->mp_scene)
- output->relayer_layer(layer, layer->m_scene_layer, scene_layer);
+ if (layer->mp_server->m_scene_layers[layer->m_scene_layer] != layer->mp_scene)
+ output->relayer_layer(layer, layer->m_scene_layer, layer->m_scene_layer);
output->arrange_layers();
}
+static inline LayerPopup_ptr
+create_layer_popup(
+ struct wlr_xdg_popup* wlr_popup,
+ LayerPopup_ptr parent,
+ Layer_ptr root,
+ Server_ptr server,
+ Model_ptr model,
+ Seat_ptr seat
+)
+{
+ LayerPopup_ptr popup = parent
+ ? new LayerPopup(wlr_popup, parent, root, server, model, seat)
+ : new LayerPopup(wlr_popup, root, server, model, seat);
+
+ if (parent)
+ parent->m_popups.push_back(popup);
+ else
+ root->m_popups.push_back(popup);
+
+ struct wlr_output* wlr_output = root->mp_layer_surface->output;
+ Output_ptr output = reinterpret_cast<Output_ptr>(wlr_output->data);
+
+ Region const& output_region = output->full_region();
+ Region const& relative_region = parent
+ ? parent->region()
+ : root->region();
+
+ struct wlr_box mappable_region = {
+ .x = -relative_region.pos.x,
+ .y = -relative_region.pos.y,
+ .width = output_region.dim.w,
+ .height = output_region.dim.h
+ };
+
+ wlr_xdg_popup_unconstrain_from_box(wlr_popup, &mappable_region);
+ popup->set_region(Region::from_box(wlr_popup->geometry));
+
+ return popup;
+}
+
+void
+Layer::handle_new_popup(struct wl_listener* listener, void* data)
+{
+ TRACE();
+
+ Layer_ptr layer = wl_container_of(listener, layer, ml_new_popup);
+ struct wlr_xdg_popup* wlr_popup = reinterpret_cast<struct wlr_xdg_popup*>(data);
+
+ create_layer_popup(
+ wlr_popup,
+ nullptr,
+ layer,
+ layer->mp_server,
+ layer->mp_model,
+ layer->mp_seat
+ );
+}
+
void
Layer::handle_destroy(struct wl_listener* listener, void*)
{
@@ -212,3 +272,199 @@ Layer::handle_destroy(struct wl_listener* listener, void*)
spdlog::info("Destroyed layer {}", layer->m_uid_formatted);
delete layer;
}
+
+static inline void
+init_layer_popup(LayerPopup_ptr popup)
+{
+ TRACE();
+
+ wl_signal_add(&popup->mp_wlr_popup->base->events.map, &popup->ml_map);
+ wl_signal_add(&popup->mp_wlr_popup->base->events.unmap, &popup->ml_unmap);
+ wl_signal_add(&popup->mp_wlr_popup->base->surface->events.commit, &popup->ml_surface_commit);
+ wl_signal_add(&popup->mp_wlr_popup->base->events.new_popup, &popup->ml_new_popup);
+ wl_signal_add(&popup->mp_wlr_popup->base->events.destroy, &popup->ml_destroy);
+}
+
+LayerPopup::LayerPopup(
+ struct wlr_xdg_popup* wlr_popup,
+ Layer_ptr parent,
+ Server_ptr server,
+ Model_ptr model,
+ Seat_ptr seat
+)
+ : mp_server(server),
+ mp_model(model),
+ mp_seat(seat),
+ mp_wlr_popup(wlr_popup),
+ mp_parent(nullptr),
+ mp_root(parent),
+ m_popups({}),
+ ml_map({ .notify = LayerPopup::handle_map }),
+ ml_unmap({ .notify = LayerPopup::handle_unmap }),
+ ml_surface_commit({ .notify = LayerPopup::handle_surface_commit }),
+ ml_new_popup({ .notify = LayerPopup::handle_new_popup }),
+ ml_destroy({ .notify = LayerPopup::handle_destroy })
+{
+ TRACE();
+ init_layer_popup(this);
+}
+
+LayerPopup::LayerPopup(
+ struct wlr_xdg_popup* wlr_popup,
+ LayerPopup_ptr parent,
+ Layer_ptr root,
+ Server_ptr server,
+ Model_ptr model,
+ Seat_ptr seat
+)
+ : mp_server(server),
+ mp_model(model),
+ mp_seat(seat),
+ mp_wlr_popup(wlr_popup),
+ mp_parent(parent),
+ mp_root(root),
+ m_popups({}),
+ ml_map({ .notify = LayerPopup::handle_map }),
+ ml_unmap({ .notify = LayerPopup::handle_unmap }),
+ ml_surface_commit({ .notify = LayerPopup::handle_surface_commit }),
+ ml_new_popup({ .notify = LayerPopup::handle_new_popup }),
+ ml_destroy({ .notify = LayerPopup::handle_destroy })
+{
+ TRACE();
+ init_layer_popup(this);
+}
+
+LayerPopup::~LayerPopup()
+{
+
+}
+
+void
+LayerPopup::set_region(Region const& region)
+{
+ m_region = region;
+}
+
+void
+LayerPopup::handle_map(struct wl_listener* listener, void*)
+{
+ TRACE();
+
+ LayerPopup_ptr popup = wl_container_of(listener, popup, ml_map);
+ struct wlr_xdg_popup* wlr_popup = popup->mp_wlr_popup;
+ Layer_ptr root = popup->mp_root;
+ LayerPopup_ptr parent = popup->mp_parent;
+ Server_ptr server = root->mp_server;
+
+ SceneLayer reference_scene_layer = parent
+ ? parent->m_scene_layer
+ : root->m_scene_layer;
+
+ popup->m_scene_layer = SceneLayer::SCENE_LAYER_POPUP;
+ popup->mp_scene = &wlr_scene_tree_create(
+ server->m_scene_layers[popup->m_scene_layer]
+ )->node;
+ wlr_popup->base->surface->data = popup->mp_scene
+ = wlr_scene_xdg_surface_create(
+ server->m_scene_layers[popup->m_scene_layer],
+ wlr_popup->base
+ );
+ popup->mp_scene->data = popup;
+
+ wlr_scene_node_reparent(
+ popup->mp_scene,
+ server->m_scene_layers[popup->m_scene_layer]
+ );
+
+ Region const& region = popup->region();
+ wlr_scene_node_set_position(
+ popup->mp_scene,
+ region.pos.x,
+ region.pos.y
+ );
+
+ if (popup->m_scene_layer == reference_scene_layer)
+ wlr_scene_node_place_above(
+ popup->mp_scene,
+ parent ? parent->mp_scene : root->mp_scene
+ );
+}
+
+void
+LayerPopup::handle_unmap(struct wl_listener*, void*)
+{
+ TRACE();
+
+}
+
+void
+LayerPopup::handle_surface_commit(struct wl_listener* listener, void*)
+{
+ TRACE();
+
+ LayerPopup_ptr popup = wl_container_of(listener, popup, ml_surface_commit);
+
+ struct wlr_xdg_popup* wlr_popup = popup->mp_wlr_popup;
+ Layer_ptr root = popup->mp_root;
+ LayerPopup_ptr parent = popup->mp_parent;
+
+ /* wlr_scene_node_reparent( */
+ /* layer->mp_scene, */
+ /* layer->mp_server->m_scene_layers[scene_layer] */
+ /* ); */
+
+ /* Output_ptr output; */
+ /* if (!wlr_output || !(output = reinterpret_cast<Output_ptr>(wlr_output->data))) */
+ /* return; */
+
+ /* if (layer_surface->current.committed == 0 && layer->m_mapped == layer_surface->mapped) */
+ /* return; */
+
+ /* layer->m_mapped = layer_surface->mapped; */
+
+ /* if (layer->mp_server->m_scene_layers[scene_layer] != layer->mp_scene) */
+ /* output->relayer_layer(layer, layer->m_scene_layer, scene_layer); */
+
+ /* output->arrange_layers(); */
+}
+
+void
+LayerPopup::handle_new_popup(struct wl_listener* listener, void* data)
+{
+ TRACE();
+
+ LayerPopup_ptr popup = wl_container_of(listener, popup, ml_new_popup);
+ struct wlr_xdg_popup* wlr_popup = reinterpret_cast<struct wlr_xdg_popup*>(data);
+
+ create_layer_popup(
+ wlr_popup,
+ popup,
+ popup->mp_root,
+ popup->mp_server,
+ popup->mp_model,
+ popup->mp_seat
+ );
+}
+
+void
+LayerPopup::handle_destroy(struct wl_listener* listener, void*)
+{
+ TRACE();
+
+ LayerPopup_ptr popup = wl_container_of(listener, popup, ml_destroy);
+
+ wl_list_remove(&popup->ml_map.link);
+ wl_list_remove(&popup->ml_unmap.link);
+ wl_list_remove(&popup->ml_surface_commit.link);
+ wl_list_remove(&popup->ml_new_popup.link);
+ wl_list_remove(&popup->ml_destroy.link);
+
+ Util::erase_remove(
+ popup->mp_parent
+ ? popup->mp_parent->m_popups
+ : popup->mp_root->m_popups,
+ popup
+ );
+
+ delete popup;
+}