commit c8f1b325571eafb69ac3eb53bdd1bcad7f1c66f0
parent 04d88a4cf48fe7dec57aa0dbe755d39fad84c39c
Author: deurzen <max@deurzen.net>
Date: Mon, 30 May 2022 09:05:14 +0200
adds layer shell creation and arrangement routines
Diffstat:
21 files changed, 618 insertions(+), 201 deletions(-)
diff --git a/include/kranewl/layer.hh b/include/kranewl/layer.hh
@@ -1,12 +0,0 @@
-#pragma once
-
-enum Layer : short {
- None = -1,
- Background = 0,
- Bottom = 1,
- Tile = 2,
- Free = 3,
- Top = 4,
- Overlay = 5,
- NoFocus = 6,
-};
diff --git a/include/kranewl/model.hh b/include/kranewl/model.hh
@@ -6,6 +6,7 @@
#include <kranewl/input/bindings.hh>
#include <kranewl/layout.hh>
#include <kranewl/placement.hh>
+#include <kranewl/tree/layer.hh>
#include <kranewl/tree/view.hh>
#include <optional>
@@ -58,6 +59,10 @@ public:
void unregister_view(View_ptr);
void destroy_view(View_ptr);
+ Layer_ptr create_layer(struct wlr_layer_surface_v1*, Output_ptr, SceneLayer);
+ void register_layer(Layer_ptr);
+ void destroy_layer(Layer_ptr);
+
void focus_view(View_ptr);
void place_view(Placement&);
void cursor_interactive(Cursor::Mode, View_ptr);
diff --git a/include/kranewl/scene-layer.hh b/include/kranewl/scene-layer.hh
@@ -0,0 +1,14 @@
+#pragma once
+
+#include <limits>
+
+enum SceneLayer : unsigned short {
+ SCENE_LAYER_NONE = std::numeric_limits<unsigned short>::max(),
+ SCENE_LAYER_BACKGROUND = 0,
+ SCENE_LAYER_BOTTOM = 1,
+ SCENE_LAYER_TILE = 2,
+ SCENE_LAYER_FREE = 3,
+ SCENE_LAYER_TOP = 4,
+ SCENE_LAYER_OVERLAY = 5,
+ SCENE_LAYER_NOFOCUS = 6,
+};
diff --git a/include/kranewl/server.hh b/include/kranewl/server.hh
@@ -2,7 +2,6 @@
#include <kranewl/geometry.hh>
#include <kranewl/input/seat.hh>
-#include <kranewl/layer.hh>
extern "C" {
#include <wlr/backend.h>
@@ -67,7 +66,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_layers;
+ std::array<struct wlr_scene_node*, 7> m_scene_layers;
Seat m_seat;
private:
diff --git a/include/kranewl/tree/layer.hh b/include/kranewl/tree/layer.hh
@@ -0,0 +1,63 @@
+#pragma once
+
+#include <kranewl/common.hh>
+#include <kranewl/geometry.hh>
+#include <kranewl/scene-layer.hh>
+
+#include <chrono>
+
+extern "C" {
+#include <wayland-server-core.h>
+}
+
+typedef class Server* Server_ptr;
+typedef class Model* Model_ptr;
+typedef class Output* Output_ptr;
+
+typedef struct Layer {
+ Layer(
+ struct wlr_layer_surface_v1*,
+ Server_ptr,
+ Model_ptr,
+ Output_ptr,
+ SceneLayer
+ );
+
+ ~Layer();
+
+ 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_destroy(struct wl_listener*, void*);
+
+ bool mapped() const { return m_mapped; }
+ void set_mapped(bool);
+
+ Region const& region() { return m_region; }
+ void set_region(Region const&);
+
+ Uid m_uid;
+ std::string m_uid_formatted;
+
+ Server_ptr mp_server;
+ Model_ptr mp_model;
+
+ Output_ptr mp_output;
+
+ struct wlr_scene_node* mp_scene;
+ SceneLayer m_scene_layer;
+ struct wlr_layer_surface_v1* mp_layer_surface;
+
+ pid_t m_pid;
+
+ struct wl_listener ml_map;
+ struct wl_listener ml_unmap;
+ struct wl_listener ml_surface_commit;
+ struct wl_listener ml_destroy;
+
+private:
+ Region m_region;
+ bool m_mapped;
+ std::chrono::time_point<std::chrono::steady_clock> m_managed_since;
+
+}* Layer_ptr;
diff --git a/include/kranewl/tree/output.hh b/include/kranewl/tree/output.hh
@@ -3,6 +3,7 @@
#include <kranewl/common.hh>
#include <kranewl/context.hh>
#include <kranewl/geometry.hh>
+#include <kranewl/scene-layer.hh>
#include <kranewl/tree/node.hh>
extern "C" {
@@ -10,9 +11,13 @@ extern "C" {
#include <wlr/types/wlr_output.h>
}
+#include <unordered_map>
+#include <vector>
+
typedef class Server* Server_ptr;
typedef class Model* Model_ptr;
typedef class Context* Context_ptr;
+typedef class Layer* Layer_ptr;
typedef class Output final : public Node {
public:
@@ -23,6 +28,7 @@ public:
struct wlr_scene_output*,
Region const&&
);
+
~Output();
static void handle_frame(struct wl_listener*, void*);
@@ -33,13 +39,21 @@ public:
void set_context(Context_ptr);
Context_ptr context() const;
+
Region full_region() const;
Region placeable_region() const;
+ void set_placeable_region(Region const&);
+
bool contains(Pos) const;
bool contains(Region) const;
void focus_at_cursor();
+ void add_layer(Layer_ptr);
+ void remove_layer(Layer_ptr);
+
+ void arrange_layers();
+
private:
Context_ptr mp_context;
Region m_full_region;
@@ -47,6 +61,8 @@ private:
bool m_cursor_focus_on_present;
+ std::unordered_map<SceneLayer, std::vector<Layer_ptr>> m_layer_map;
+
public:
Server_ptr mp_server;
Model_ptr mp_model;
diff --git a/include/kranewl/tree/popup.hh b/include/kranewl/tree/popup.hh
@@ -1,14 +0,0 @@
-#pragma once
-
-#include <kranewl/tree/view.hh>
-
-struct PopupViewChild final : public ViewChild {
- PopupViewChild();
- ~PopupViewChild();
-
- struct wlr_xdg_popup* mp_wlr_xdg_popup;
-
- struct wl_listener ml_new_popup;
- struct wl_listener ml_destroy;
-
-};
diff --git a/include/kranewl/tree/subsurface.hh b/include/kranewl/tree/subsurface.hh
@@ -1,11 +0,0 @@
-#pragma once
-
-#include <kranewl/tree/view.hh>
-
-struct SubsurfaceViewChild final : public ViewChild {
- SubsurfaceViewChild();
- ~SubsurfaceViewChild();
-
- struct wl_listener ml_destroy;
-
-};
diff --git a/include/kranewl/tree/surface.hh b/include/kranewl/tree/surface.hh
@@ -1,46 +0,0 @@
-#pragma once
-
-#include <kranewl/common.hh>
-
-enum class SurfaceType {
- XDGShell,
- LayerShell,
- X11Managed,
- X11Unmanaged
-};
-
-struct Surface {
- Surface(struct wlr_xdg_surface* xdg, bool toplevel)
- : type{toplevel
- ? SurfaceType::XDGShell
- : SurfaceType::LayerShell},
- xdg{xdg}
- {}
-
- Surface(struct wlr_xwayland_surface* xwayland, bool managed)
- : type{managed
- ? SurfaceType::X11Managed
- : SurfaceType::X11Unmanaged},
- xwayland{xwayland}
- {}
-
- Uid
- uid() const
- {
- switch (type) {
- case SurfaceType::XDGShell: // fallthrough
- case SurfaceType::LayerShell: return reinterpret_cast<Uid>(xdg);
- case SurfaceType::X11Managed: // fallthrough
- case SurfaceType::X11Unmanaged: return reinterpret_cast<Uid>(xwayland);
- default: break;
- }
-
- return 0;
- }
-
- SurfaceType type;
- union {
- struct wlr_xdg_surface* xdg;
- struct wlr_xwayland_surface* xwayland;
- };
-};
diff --git a/include/kranewl/tree/view.hh b/include/kranewl/tree/view.hh
@@ -3,9 +3,7 @@
#include <kranewl/common.hh>
#include <kranewl/decoration.hh>
#include <kranewl/geometry.hh>
-#include <kranewl/layer.hh>
-#include <kranewl/model.hh>
-#include <kranewl/tree/surface.hh>
+#include <kranewl/scene-layer.hh>
#include <vector>
#include <chrono>
@@ -88,7 +86,7 @@ typedef struct View {
void map();
void unmap();
void tile(Toggle);
- void relayer(Layer);
+ void relayer(SceneLayer);
void raise() const;
void lower() const;
@@ -123,6 +121,10 @@ typedef struct View {
void set_iconified(bool);
void set_disowned(bool);
+ std::chrono::time_point<std::chrono::steady_clock> last_focused() const;
+ std::chrono::time_point<std::chrono::steady_clock> last_touched() const;
+ std::chrono::time_point<std::chrono::steady_clock> managed_since() const;
+
uint32_t free_decoration_to_wlr_edges() const;
uint32_t tile_decoration_to_wlr_edges() const;
Region const& free_region() const { return m_free_region; }
@@ -184,10 +186,6 @@ typedef struct View {
pid_t m_pid;
- std::chrono::time_point<std::chrono::steady_clock> m_last_focused;
- std::chrono::time_point<std::chrono::steady_clock> m_last_touched;
- std::chrono::time_point<std::chrono::steady_clock> m_managed_since;
-
protected:
struct {
@@ -222,55 +220,16 @@ private:
bool m_iconified;
bool m_disowned;
- Layer m_layer;
+ SceneLayer m_scene_layer;
OutsideState m_outside_state;
+ std::chrono::time_point<std::chrono::steady_clock> m_last_focused;
+ std::chrono::time_point<std::chrono::steady_clock> m_last_touched;
+ std::chrono::time_point<std::chrono::steady_clock> m_managed_since;
+
void set_inner_region(Region const&);
void set_active_region(Region const&);
void set_active_pos(Pos const&);
}* View_ptr;
-
-typedef struct ViewChild* ViewChild_ptr;
-typedef struct SubsurfaceViewChild* SubsurfaceViewChild_ptr;
-typedef struct PopupViewChild* PopupViewChild_ptr;
-
-typedef struct ViewChild {
- enum class Type {
- Subsurface,
- Popup,
- };
-
-protected:
- ViewChild(SubsurfaceViewChild_ptr);
- ViewChild(PopupViewChild_ptr);
-
- virtual ~ViewChild();
-
-public:
- Uid m_uid;
- Type m_type;
-
- View_ptr mp_view;
- ViewChild_ptr mp_parent;
- std::vector<ViewChild_ptr> m_children;
-
- struct wlr_scene_node* mp_scene;
- struct wlr_scene_node* mp_scene_surface;
-
- bool m_mapped;
-
- float m_alpha;
- uint32_t m_resize;
-
- pid_t m_pid;
-
- struct wl_listener ml_surface_commit;
- struct wl_listener ml_surface_new_subsurface;
- struct wl_listener ml_surface_map;
- struct wl_listener ml_surface_unmap;
- struct wl_listener ml_surface_destroy;
- struct wl_listener ml_view_unmap;
-
-}* ViewChild_ptr;
diff --git a/include/kranewl/util.hh b/include/kranewl/util.hh
@@ -132,4 +132,23 @@ namespace Util
return c.empty() ? 0 : c.size() - 1;
}
+ // https://stackoverflow.com/a/28139075
+ template <typename T>
+ struct reversion_wrapper { T& iterable; };
+
+ template <typename T>
+ auto begin(reversion_wrapper<T> w) { return std::rbegin(w.iterable); }
+
+ template <typename T>
+ auto end(reversion_wrapper<T> w)
+ {
+ return std::rend(w.iterable);
+ }
+
+ template <typename T>
+ reversion_wrapper<T> reverse(T&& iterable)
+ {
+ return { iterable };
+ }
+
}
diff --git a/src/kranewl/input/cursor.cc b/src/kranewl/input/cursor.cc
@@ -3,7 +3,8 @@
#include <kranewl/input/cursor.hh>
#include <kranewl/input/seat.hh>
-#include <kranewl/layer.hh>
+#include <kranewl/model.hh>
+#include <kranewl/scene-layer.hh>
#include <kranewl/server.hh>
#include <kranewl/tree/view.hh>
#include <kranewl/util.hh>
@@ -79,17 +80,17 @@ view_at(
double* sx, double* sy
)
{
- static std::vector<Layer> focus_order = {
- Layer::Overlay,
- Layer::Top,
- Layer::Free,
- Layer::Tile,
- Layer::Bottom,
+ static std::vector<SceneLayer> focus_order = {
+ SCENE_LAYER_OVERLAY,
+ SCENE_LAYER_TOP,
+ SCENE_LAYER_FREE,
+ SCENE_LAYER_TILE,
+ SCENE_LAYER_BOTTOM,
};
struct wlr_scene_node* node;
for (auto const& layer : focus_order) {
- if ((node = wlr_scene_node_at(server->m_layers[layer], lx, ly, sx, sy))) {
+ if ((node = wlr_scene_node_at(server->m_scene_layers[layer], lx, ly, sx, sy))) {
if (node->type != WLR_SCENE_NODE_SURFACE)
return nullptr;
diff --git a/src/kranewl/layout.cc b/src/kranewl/layout.cc
@@ -971,7 +971,7 @@ LayoutHandler::arrange_paper(
return true;
}
- return lhs->m_last_focused < rhs->m_last_focused;
+ return lhs->last_focused() < rhs->last_focused();
}
);
diff --git a/src/kranewl/model.cc b/src/kranewl/model.cc
@@ -429,7 +429,7 @@ Model::shuffle_main(Direction direction)
mp_workspace->begin(),
mp_workspace->begin() + main_count,
[](View_ptr view1, View_ptr view2) -> bool {
- return view1->m_last_touched < view2->m_last_touched;
+ return view1->last_touched() < view2->last_touched();
}
);
@@ -465,7 +465,7 @@ Model::shuffle_stack(Direction direction)
mp_workspace->begin() + main_count,
mp_workspace->end(),
[](View_ptr view1, View_ptr view2) -> bool {
- return view1->m_last_touched < view2->m_last_touched;
+ return view1->last_touched() < view2->last_touched();
}
);
@@ -1844,6 +1844,45 @@ Model::destroy_view(View_ptr view)
spdlog::info("Destroyed view {}", view->m_uid_formatted);
}
+Layer_ptr
+Model::create_layer(
+ struct wlr_layer_surface_v1* layer_surface,
+ Output_ptr output,
+ SceneLayer scene_layer
+)
+{
+ TRACE();
+
+ Layer_ptr layer = new Layer(
+ layer_surface,
+ mp_server,
+ this,
+ output,
+ scene_layer
+ );
+
+ return layer;
+}
+
+void
+Model::register_layer(Layer_ptr layer)
+{
+ TRACE();
+
+ layer->mp_output->add_layer(layer);
+ spdlog::info("Registered layer {}", layer->m_uid_formatted);
+}
+
+void
+Model::destroy_layer(Layer_ptr layer)
+{
+ TRACE();
+
+ layer->mp_output->remove_layer(layer);
+ delete layer;
+ spdlog::info("Destroyed layer {}", layer->m_uid_formatted);
+}
+
bool
Model::is_free(View_ptr view) const
{
diff --git a/src/kranewl/server.cc b/src/kranewl/server.cc
@@ -102,7 +102,7 @@ Server::Server(Model_ptr model)
wlr_scene_attach_output_layout(scene, mp_output_layout);
return scene;
}()),
- m_layers{
+ m_scene_layers{
&wlr_scene_tree_create(&mp_scene->node)->node,
&wlr_scene_tree_create(&mp_scene->node)->node,
&wlr_scene_tree_create(&mp_scene->node)->node,
@@ -400,10 +400,58 @@ Server::handle_new_xdg_surface(struct wl_listener* listener, void* data)
}
void
-Server::handle_new_layer_shell_surface(struct wl_listener*, void*)
+Server::handle_new_layer_shell_surface(struct wl_listener* listener, void* data)
{
TRACE();
+ Server_ptr server = wl_container_of(listener, server, ml_new_layer_shell_surface);
+ struct wlr_layer_surface_v1* layer_surface
+ = reinterpret_cast<struct wlr_layer_surface_v1*>(data);
+
+ if (!layer_surface->output)
+ layer_surface->output = server->mp_model->mp_output->mp_wlr_output;
+
+ SceneLayer scene_layer;
+ switch (layer_surface->pending.layer) {
+ case ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND:
+ scene_layer = SCENE_LAYER_BACKGROUND;
+ break;
+ case ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM:
+ scene_layer = SCENE_LAYER_BOTTOM;
+ break;
+ case ZWLR_LAYER_SHELL_V1_LAYER_TOP:
+ scene_layer = SCENE_LAYER_TOP;
+ break;
+ case ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY:
+ scene_layer = SCENE_LAYER_OVERLAY;
+ break;
+ default:
+ spdlog::error("No applicable scene layer found for layer surface");
+ scene_layer = SCENE_LAYER_NONE;
+ break;
+ }
+
+ Output_ptr output = reinterpret_cast<Output_ptr>(layer_surface->output->data);
+ Layer_ptr layer = server->mp_model->create_layer(
+ layer_surface,
+ output,
+ scene_layer
+ );
+
+ layer_surface->data = layer;
+ layer_surface->surface->data = layer->mp_scene
+ = wlr_scene_subsurface_tree_create(
+ server->m_scene_layers[scene_layer],
+ layer_surface->surface
+ );
+ layer->mp_scene->data = layer;
+
+ server->mp_model->register_layer(layer);
+
+ struct wlr_layer_surface_v1_state initial_state = layer_surface->current;
+ layer_surface->current = layer_surface->pending;
+ output->arrange_layers();
+ layer_surface->current = initial_state;
}
void
diff --git a/src/kranewl/tree/layer.cc b/src/kranewl/tree/layer.cc
@@ -0,0 +1,80 @@
+#include <trace.hh>
+
+#include <kranewl/tree/layer.hh>
+
+// https://github.com/swaywm/wlroots/issues/682
+#define namespace namespace_
+extern "C" {
+#include <wlr/types/wlr_layer_shell_v1.h>
+}
+#undef namespace
+
+Layer::Layer(
+ struct wlr_layer_surface_v1* layer_surface,
+ Server_ptr server,
+ Model_ptr model,
+ Output_ptr output,
+ SceneLayer scene_layer
+)
+ : m_uid(reinterpret_cast<std::uintptr_t>(layer_surface)),
+ m_uid_formatted([this]() {
+ std::stringstream uid_ss;
+ uid_ss << "0x" << std::hex << m_uid;
+ return uid_ss.str();
+ }()),
+ mp_server(server),
+ mp_model(model),
+ mp_output(output),
+ m_scene_layer(scene_layer),
+ mp_layer_surface(layer_surface),
+ ml_map({ .notify = Layer::handle_map }),
+ ml_unmap({ .notify = Layer::handle_unmap }),
+ ml_surface_commit({ .notify = Layer::handle_surface_commit }),
+ ml_destroy({ .notify = Layer::handle_destroy }),
+ m_mapped(false),
+ m_managed_since(std::chrono::steady_clock::now())
+{
+ 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.new_subsurface, &ml_destroy);
+ wl_signal_add(&mp_layer_surface->events.destroy, &ml_destroy);
+}
+
+Layer::~Layer()
+{}
+
+void
+Layer::set_mapped(bool mapped)
+{
+ m_mapped = mapped;
+}
+
+void
+Layer::set_region(Region const& region)
+{
+ m_region = region;
+}
+
+void
+Layer::handle_map(struct wl_listener*, void*)
+{
+
+}
+
+void
+Layer::handle_unmap(struct wl_listener*, void*)
+{
+
+}
+
+void
+Layer::handle_surface_commit(struct wl_listener*, void*)
+{
+
+}
+
+void
+Layer::handle_destroy(struct wl_listener*, void*)
+{
+
+}
diff --git a/src/kranewl/tree/output.cc b/src/kranewl/tree/output.cc
@@ -2,8 +2,9 @@
#include <kranewl/model.hh>
#include <kranewl/server.hh>
-#include <kranewl/workspace.hh>
#include <kranewl/tree/output.hh>
+#include <kranewl/util.hh>
+#include <kranewl/workspace.hh>
// https://github.com/swaywm/wlroots/issues/682
#include <pthread.h>
@@ -11,14 +12,18 @@
#define namespace namespace_
#define static
extern "C" {
+#include <wlr/types/wlr_layer_shell_v1.h>
#include <wlr/types/wlr_output_damage.h>
#include <wlr/types/wlr_output_layout.h>
#include <wlr/types/wlr_scene.h>
+#include <wlr/types/wlr_seat.h>
}
#undef static
#undef class
#undef namespace
+#include <vector>
+
Output::Output(
Server_ptr server,
Model_ptr model,
@@ -34,6 +39,12 @@ Output::Output(
mp_model(model),
m_dirty(true),
m_cursor_focus_on_present(false),
+ m_layer_map{
+ { SCENE_LAYER_BACKGROUND, {} },
+ { SCENE_LAYER_BOTTOM, {} },
+ { SCENE_LAYER_TOP, {} },
+ { SCENE_LAYER_OVERLAY, {} }
+ },
mp_wlr_output(wlr_output),
mp_wlr_scene_output(wlr_scene_output),
ml_frame({ .notify = Output::handle_frame }),
@@ -158,6 +169,12 @@ Output::placeable_region() const
return m_placeable_region;
}
+void
+Output::set_placeable_region(Region const& region)
+{
+ m_placeable_region = region;
+}
+
bool
Output::contains(Pos pos) const
{
@@ -175,3 +192,256 @@ Output::focus_at_cursor()
{
m_cursor_focus_on_present = true;
}
+
+void
+Output::add_layer(Layer_ptr layer)
+{
+ TRACE();
+ m_layer_map[layer->m_scene_layer].push_back(layer);
+}
+
+void
+Output::remove_layer(Layer_ptr layer)
+{
+ TRACE();
+ Util::erase_remove(m_layer_map.at(layer->m_scene_layer), layer);
+}
+
+static inline void
+propagate_exclusivity(
+ Region& placeable_region,
+ uint32_t anchor,
+ int32_t exclusive_zone,
+ int32_t margin_top,
+ int32_t margin_right,
+ int32_t margin_bottom,
+ int32_t margin_left
+)
+{
+ TRACE();
+
+ struct Edge {
+ uint32_t singular_anchor;
+ uint32_t anchor_triplet;
+ int* positive_axis;
+ int* negative_axis;
+ int margin;
+ };
+
+ // https://github.com/swaywm/sway/blob/master/sway/desktop/layer_shell.c
+ const std::vector<Edge> edges = {
+ {
+ .singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP,
+ .anchor_triplet =
+ ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT |
+ ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT |
+ ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP,
+ .positive_axis = &placeable_region.pos.y,
+ .negative_axis = &placeable_region.dim.h,
+ .margin = margin_top,
+ },
+ {
+ .singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM,
+ .anchor_triplet =
+ ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT |
+ ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT |
+ ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM,
+ .positive_axis = NULL,
+ .negative_axis = &placeable_region.dim.h,
+ .margin = margin_bottom,
+ },
+ {
+ .singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT,
+ .anchor_triplet =
+ ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT |
+ ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP |
+ ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM,
+ .positive_axis = &placeable_region.pos.x,
+ .negative_axis = &placeable_region.dim.w,
+ .margin = margin_left,
+ },
+ {
+ .singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT,
+ .anchor_triplet =
+ ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT |
+ ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP |
+ ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM,
+ .positive_axis = NULL,
+ .negative_axis = &placeable_region.dim.w,
+ .margin = margin_right,
+ },
+ };
+
+ for (auto const& edge : edges) {
+ if ((anchor == edge.singular_anchor || anchor == edge.anchor_triplet)
+ && exclusive_zone + edge.margin > 0)
+ {
+ if (edge.positive_axis)
+ *edge.positive_axis += exclusive_zone + edge.margin;
+
+ if (edge.negative_axis)
+ *edge.negative_axis -= exclusive_zone + edge.margin;
+
+ break;
+ }
+ }
+}
+
+static inline void
+arrange_layer(
+ Output_ptr output,
+ Region& placeable_region,
+ std::vector<Layer_ptr> const& layers,
+ bool exclusive
+)
+{
+ TRACE();
+
+ static constexpr uint32_t full_width
+ = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT;
+ static constexpr uint32_t full_height
+ = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM;
+
+ for (Layer_ptr layer : layers) {
+ struct wlr_layer_surface_v1* layer_surface = layer->mp_layer_surface;
+ struct wlr_layer_surface_v1_state* state = &layer_surface->current;
+
+ if (exclusive != (state->exclusive_zone > 0))
+ continue;
+
+ Region region = {
+ .dim = {
+ .w = state->desired_width,
+ .h = state->desired_height,
+ }
+ };
+
+ Region bounds = state->exclusive_zone == -1
+ ? output->full_region()
+ : placeable_region;
+
+ // horizontal axis
+ if ((state->anchor & full_width) && region.dim.w == 0) {
+ region.pos.x = bounds.pos.x;
+ region.dim.w = bounds.dim.w;
+ } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT))
+ region.pos.x = bounds.pos.x;
+ else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT))
+ region.pos.x = bounds.pos.x + (bounds.dim.w - region.dim.w);
+ else
+ region.pos.x = bounds.pos.x + ((bounds.dim.w / 2) - (region.dim.w / 2));
+
+ // vertical axis
+ if ((state->anchor & full_height) && region.dim.h == 0) {
+ region.pos.y = bounds.pos.y;
+ region.dim.h = bounds.dim.h;
+ } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP))
+ region.pos.y = bounds.pos.y;
+ else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM))
+ region.pos.y = bounds.pos.y + (bounds.dim.h - region.dim.h);
+ else
+ region.pos.y = bounds.pos.y + ((bounds.dim.h / 2) - (region.dim.h / 2));
+
+ { // margin
+ if ((state->anchor & full_width) == full_width) {
+ region.pos.x += state->margin.left;
+ region.dim.w -= state->margin.left + state->margin.right;
+ } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT))
+ region.pos.x += state->margin.left;
+ else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT))
+ region.pos.x -= state->margin.right;
+
+ if ((state->anchor & full_height) == full_height) {
+ region.pos.y += state->margin.top;
+ region.dim.h -= state->margin.top + state->margin.bottom;
+ } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP))
+ region.pos.y += state->margin.top;
+ else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM))
+ region.pos.y -= state->margin.bottom;
+ }
+
+ if (region.dim.w < 0 || region.dim.h < 0) {
+ wlr_layer_surface_v1_destroy(layer_surface);
+ continue;
+ }
+
+ layer->set_region(region);
+
+ if (state->exclusive_zone > 0)
+ propagate_exclusivity(
+ placeable_region,
+ state->anchor,
+ state->exclusive_zone,
+ state->margin.top,
+ state->margin.right,
+ state->margin.bottom,
+ state->margin.left
+ );
+
+ wlr_scene_node_set_position(layer->mp_scene, region.pos.x, region.pos.y);
+ wlr_layer_surface_v1_configure(layer_surface, region.dim.w, region.dim.h);
+ }
+}
+
+void
+Output::arrange_layers()
+{
+ TRACE();
+
+ static const std::vector<SceneLayer> scene_layers_top_bottom = {
+ SCENE_LAYER_OVERLAY,
+ SCENE_LAYER_TOP,
+ SCENE_LAYER_BOTTOM,
+ SCENE_LAYER_BACKGROUND,
+ };
+
+ static const std::vector<SceneLayer> scene_layers_super_shell = {
+ SCENE_LAYER_OVERLAY,
+ SCENE_LAYER_TOP,
+ };
+
+ Region placeable_region = m_full_region;
+ struct wlr_keyboard* keyboard
+ = wlr_seat_get_keyboard(mp_server->m_seat.mp_wlr_seat);
+
+ // exclusive surfaces
+ for (SceneLayer scene_layer : scene_layers_top_bottom)
+ arrange_layer(this, placeable_region, m_layer_map.at(scene_layer), true);
+
+ // TODO: re-apply layout if placeable region changed
+ if (mp_context && m_placeable_region != placeable_region) {
+ set_placeable_region(placeable_region);
+ mp_model->apply_layout(mp_context->workspace());
+ }
+
+ // non-exclusive surfaces
+ for (SceneLayer scene_layer : scene_layers_top_bottom)
+ arrange_layer(this, placeable_region, m_layer_map.at(scene_layer), false);
+
+ for (SceneLayer scene_layer : scene_layers_super_shell)
+ for (Layer_ptr layer : Util::reverse(m_layer_map[scene_layer]))
+ if (layer->mp_layer_surface->current.keyboard_interactive
+ && layer->mp_layer_surface->mapped)
+ {
+ mp_server->relinquish_focus();
+
+ if (keyboard)
+ wlr_seat_keyboard_notify_enter(
+ mp_server->m_seat.mp_wlr_seat,
+ layer->mp_layer_surface->surface,
+ keyboard->keycodes,
+ keyboard->num_keycodes,
+ &keyboard->modifiers
+ );
+ else
+ wlr_seat_keyboard_notify_enter(
+ mp_server->m_seat.mp_wlr_seat,
+ layer->mp_layer_surface->surface,
+ nullptr,
+ 0,
+ nullptr
+ );
+
+ return;
+ }
+}
diff --git a/src/kranewl/tree/popup.cc b/src/kranewl/tree/popup.cc
@@ -1,13 +0,0 @@
-#include <kranewl/tree/view.hh>
-#include <kranewl/tree/popup.hh>
-
-PopupViewChild::PopupViewChild()
- : ViewChild(this)
-{
-
-}
-
-PopupViewChild::~PopupViewChild()
-{
-
-}
diff --git a/src/kranewl/tree/subsurface.cc b/src/kranewl/tree/subsurface.cc
@@ -1,13 +0,0 @@
-#include <kranewl/tree/view.hh>
-#include <kranewl/tree/subsurface.hh>
-
-SubsurfaceViewChild::SubsurfaceViewChild()
- : ViewChild(this)
-{
-
-}
-
-SubsurfaceViewChild::~SubsurfaceViewChild()
-{
-
-}
diff --git a/src/kranewl/tree/view.cc b/src/kranewl/tree/view.cc
@@ -1,8 +1,8 @@
#include <trace.hh>
-#include <kranewl/layer.hh>
-#include <kranewl/server.hh>
#include <kranewl/model.hh>
+#include <kranewl/scene-layer.hh>
+#include <kranewl/server.hh>
#include <kranewl/tree/view.hh>
#include <kranewl/tree/xdg_view.hh>
@@ -70,7 +70,7 @@ View::View(
m_iconifyable(true),
m_iconified(false),
m_disowned(false),
- m_layer(Layer::None),
+ m_scene_layer(SCENE_LAYER_NONE),
m_last_focused(std::chrono::steady_clock::now()),
m_last_touched(std::chrono::steady_clock::now()),
m_managed_since(std::chrono::steady_clock::now()),
@@ -122,7 +122,7 @@ View::View(
m_iconifyable(true),
m_iconified(false),
m_disowned(false),
- m_layer(Layer::None),
+ m_scene_layer(SCENE_LAYER_NONE),
m_last_focused(std::chrono::steady_clock::now()),
m_last_touched(std::chrono::steady_clock::now()),
m_managed_since(std::chrono::steady_clock::now())
@@ -268,6 +268,24 @@ View::set_disowned(bool disowned)
}
}
+std::chrono::time_point<std::chrono::steady_clock>
+View::last_focused() const
+{
+ return m_last_focused;
+}
+
+std::chrono::time_point<std::chrono::steady_clock>
+View::last_touched() const
+{
+ return m_last_touched;
+}
+
+std::chrono::time_point<std::chrono::steady_clock>
+View::managed_since() const
+{
+ return m_managed_since;
+}
+
void
View::map()
{
@@ -300,7 +318,7 @@ View::tile(Toggle toggle)
set_floating(false);
if (!m_fullscreen)
- relayer(Layer::Tile);
+ relayer(SCENE_LAYER_TILE);
break;
}
@@ -311,7 +329,7 @@ View::tile(Toggle toggle)
set_floating(true);
if (!m_fullscreen)
- relayer(Layer::Free);
+ relayer(SCENE_LAYER_FREE);
break;
}
@@ -329,16 +347,16 @@ View::tile(Toggle toggle)
}
void
-View::relayer(Layer layer)
+View::relayer(SceneLayer layer)
{
- if (layer == m_layer)
+ if (layer == m_scene_layer)
return;
- m_layer = layer;
+ m_scene_layer = layer;
wlr_scene_node_reparent(
mp_scene,
- mp_server->m_layers[layer]
+ mp_server->m_scene_layers[layer]
);
}
@@ -541,14 +559,3 @@ View::set_inner_region(Region const& region)
m_inner_region.dim = region.dim;
}
}
-
-ViewChild::ViewChild(SubsurfaceViewChild_ptr)
- : m_type(Type::Subsurface)
-{}
-
-ViewChild::ViewChild(PopupViewChild_ptr)
- : m_type(Type::Popup)
-{}
-
-ViewChild::~ViewChild()
-{}
diff --git a/src/kranewl/tree/xdg_view.cc b/src/kranewl/tree/xdg_view.cc
@@ -1,8 +1,8 @@
#include <trace.hh>
#include <kranewl/context.hh>
-#include <kranewl/layer.hh>
#include <kranewl/model.hh>
+#include <kranewl/scene-layer.hh>
#include <kranewl/server.hh>
#include <kranewl/tree/output.hh>
#include <kranewl/tree/view.hh>
@@ -376,14 +376,20 @@ XDGView::handle_map(struct wl_listener* listener, void* data)
view->free_decoration_to_wlr_edges()
);
- view->mp_scene = &wlr_scene_tree_create(server->m_layers[Layer::Tile])->node;
+ view->mp_scene = &wlr_scene_tree_create(
+ server->m_scene_layers[SCENE_LAYER_TILE]
+ )->node;
view->mp_wlr_surface->data = view->mp_scene_surface = wlr_scene_xdg_surface_create(
view->mp_scene,
view->mp_wlr_xdg_surface
);
view->mp_scene_surface->data = view;
- view->relayer(view->floating() ? Layer::Free : Layer::Tile);
+ view->relayer(
+ view->floating()
+ ? SCENE_LAYER_FREE
+ : SCENE_LAYER_TILE
+ );
for (std::size_t i = 0; i < 4; ++i) {
view->m_protrusions[i] = wlr_scene_rect_create(