kranewl

A wlroots-based dynamic Wayland compositor, written in C++, configurable with Lua
git clone git://git.deurzen.net/kranewl
Log | Files | Refs | LICENSE

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:
Dinclude/kranewl/layer.hh | 12------------
Minclude/kranewl/model.hh | 5+++++
Ainclude/kranewl/scene-layer.hh | 14++++++++++++++
Minclude/kranewl/server.hh | 3+--
Ainclude/kranewl/tree/layer.hh | 63+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Minclude/kranewl/tree/output.hh | 16++++++++++++++++
Dinclude/kranewl/tree/popup.hh | 14--------------
Dinclude/kranewl/tree/subsurface.hh | 11-----------
Dinclude/kranewl/tree/surface.hh | 46----------------------------------------------
Minclude/kranewl/tree/view.hh | 63+++++++++++----------------------------------------------------
Minclude/kranewl/util.hh | 19+++++++++++++++++++
Msrc/kranewl/input/cursor.cc | 17+++++++++--------
Msrc/kranewl/layout.cc | 2+-
Msrc/kranewl/model.cc | 43+++++++++++++++++++++++++++++++++++++++++--
Msrc/kranewl/server.cc | 52++++++++++++++++++++++++++++++++++++++++++++++++++--
Asrc/kranewl/tree/layer.cc | 80+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/kranewl/tree/output.cc | 272++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Dsrc/kranewl/tree/popup.cc | 13-------------
Dsrc/kranewl/tree/subsurface.cc | 13-------------
Msrc/kranewl/tree/view.cc | 49++++++++++++++++++++++++++++---------------------
Msrc/kranewl/tree/xdg_view.cc | 12+++++++++---
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(