commit 99c5c6058b30e11dbdfd313190a75835a9186e29
parent c8f1b325571eafb69ac3eb53bdd1bcad7f1c66f0
Author: deurzen <max@deurzen.net>
Date: Mon, 30 May 2022 12:51:59 +0200
implements full layer shell compliance
Diffstat:
15 files changed, 242 insertions(+), 154 deletions(-)
diff --git a/include/kranewl/input/cursor.hh b/include/kranewl/input/cursor.hh
@@ -62,6 +62,8 @@ typedef struct Cursor {
void initiate_cursor_interactive(Mode, View_ptr);
void abort_cursor_interactive();
+ void process_cursor_motion(uint32_t time);
+
static void handle_cursor_motion(struct wl_listener*, void*);
static void handle_cursor_motion_absolute(struct wl_listener*, void*);
static void handle_cursor_button(struct wl_listener*, void*);
diff --git a/include/kranewl/model.hh b/include/kranewl/model.hh
@@ -61,10 +61,13 @@ public:
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 refocus();
void place_view(Placement&);
+
+ void focus_output(Output_ptr);
+
void cursor_interactive(Cursor::Mode, View_ptr);
void abort_cursor_interactive();
diff --git a/include/kranewl/tree/layer.hh b/include/kranewl/tree/layer.hh
@@ -3,6 +3,7 @@
#include <kranewl/common.hh>
#include <kranewl/geometry.hh>
#include <kranewl/scene-layer.hh>
+#include <kranewl/tree/node.hh>
#include <chrono>
@@ -14,7 +15,7 @@ typedef class Server* Server_ptr;
typedef class Model* Model_ptr;
typedef class Output* Output_ptr;
-typedef struct Layer {
+typedef struct Layer : public Node {
Layer(
struct wlr_layer_surface_v1*,
Server_ptr,
@@ -57,7 +58,7 @@ typedef struct Layer {
private:
Region m_region;
- bool m_mapped;
+ int m_mapped;
std::chrono::time_point<std::chrono::steady_clock> m_managed_since;
}* Layer_ptr;
diff --git a/include/kranewl/tree/node.hh b/include/kranewl/tree/node.hh
@@ -1,51 +1,33 @@
#pragma once
-#include <kranewl/common.hh>
-
-extern "C" {
-#include <wayland-server-core.h>
-}
-
-typedef class Root* Root_ptr;
-typedef class Output* Output_ptr;
-typedef class Context* Context_ptr;
-typedef class Workspace* Workspace_ptr;
-typedef struct Container* Container_ptr;
-
typedef struct Node {
enum class Type {
- Root,
- Output,
- Context,
- Workspace,
- Container,
+ XDGShell,
+ LayerShell,
+#ifdef XWAYLAND
+ XWaylandManaged,
+ XWaylandUnmanaged,
+#endif
};
+ virtual bool is_focusable() const
+ {
+#ifdef XWAYLAND
+ return m_type == Type::XDGShell
+ || m_type == Type::XWaylandManaged;
+#else
+ return m_type == Type::XDGShell;
+#endif
+ }
+
protected:
- Node(Root_ptr);
- Node(Output_ptr);
- Node(Context_ptr);
- Node(Workspace_ptr);
- Node(Container_ptr);
- ~Node();
+ Node(Type type)
+ : m_type(type)
+ {}
-public:
- Uid m_uid;
+ ~Node()
+ {}
Type m_type;
- union {
- Root_ptr m_root;
- Output_ptr m_output;
- Context_ptr m_context;
- Workspace_ptr m_workspace;
- Container_ptr m_container;
- };
-
- bool m_destroying;
- bool m_dirty;
-
- struct {
- struct wl_signal destroy;
- } m_events;
}* Node_ptr;
diff --git a/include/kranewl/tree/output.hh b/include/kranewl/tree/output.hh
@@ -19,7 +19,7 @@ typedef class Model* Model_ptr;
typedef class Context* Context_ptr;
typedef class Layer* Layer_ptr;
-typedef class Output final : public Node {
+typedef class Output final {
public:
Output(
Server_ptr,
@@ -51,6 +51,7 @@ public:
void add_layer(Layer_ptr);
void remove_layer(Layer_ptr);
+ void relayer_layer(Layer_ptr, SceneLayer, SceneLayer);
void arrange_layers();
diff --git a/include/kranewl/tree/view.hh b/include/kranewl/tree/view.hh
@@ -4,6 +4,7 @@
#include <kranewl/decoration.hh>
#include <kranewl/geometry.hh>
#include <kranewl/scene-layer.hh>
+#include <kranewl/tree/node.hh>
#include <vector>
#include <chrono>
@@ -25,7 +26,7 @@ typedef struct XWaylandView* XWaylandView_ptr;
#endif
typedef struct View* View_ptr;
-typedef struct View {
+typedef struct View : public Node {
static constexpr Dim MIN_VIEW_DIM = Dim{25, 10};
static constexpr Dim PREFERRED_INIT_VIEW_DIM = Dim{480, 260};
@@ -39,13 +40,6 @@ typedef struct View {
Urgent
};
- enum class Type {
- XDGShell,
-#ifdef XWAYLAND
- XWayland,
-#endif
- };
-
View(
XDGView_ptr,
Uid,
@@ -162,8 +156,6 @@ typedef struct View {
Uid m_uid;
std::string m_uid_formatted;
- Type m_type;
-
Server_ptr mp_server;
Model_ptr mp_model;
Seat_ptr mp_seat;
diff --git a/src/kranewl/input/cursor.cc b/src/kranewl/input/cursor.cc
@@ -23,8 +23,8 @@ extern "C" {
#include <wlr/types/wlr_xcursor_manager.h>
}
#undef static
-#undef class
#undef namespace
+#undef class
#include <algorithm>
@@ -99,7 +99,10 @@ view_at(
while (node && !node->data)
node = node->parent;
- return reinterpret_cast<View_ptr>(node->data);
+ if (node && node->data && static_cast<Node_ptr>(node->data)->is_focusable())
+ return reinterpret_cast<View_ptr>(node->data);
+
+ return nullptr;
}
}
@@ -291,20 +294,20 @@ cursor_motion_to_client(
prev_view = view;
}
-static inline void
-process_cursor_motion(Cursor_ptr cursor, uint32_t time)
+void
+Cursor::process_cursor_motion(uint32_t time)
{
struct wlr_drag_icon* icon;
- if (cursor->mp_seat->mp_wlr_seat->drag && (icon = cursor->mp_seat->mp_wlr_seat->drag->icon))
+ if (mp_seat->mp_wlr_seat->drag && (icon = mp_seat->mp_wlr_seat->drag->icon))
wlr_scene_node_set_position(
reinterpret_cast<struct wlr_scene_node*>(icon->data),
- cursor->mp_wlr_cursor->x + icon->surface->sx,
- cursor->mp_wlr_cursor->y + icon->surface->sy
+ mp_wlr_cursor->x + icon->surface->sx,
+ mp_wlr_cursor->y + icon->surface->sy
);
- switch (cursor->m_cursor_mode) {
- case Cursor::Mode::Move: process_cursor_move(cursor, time); return;
- case Cursor::Mode::Resize: process_cursor_resize(cursor, time); return;
+ switch (m_cursor_mode) {
+ case Cursor::Mode::Move: process_cursor_move(this, time); return;
+ case Cursor::Mode::Resize: process_cursor_resize(this, time); return;
case Cursor::Mode::Passthrough: // fallthrough
default: break;
}
@@ -313,22 +316,21 @@ process_cursor_motion(Cursor_ptr cursor, uint32_t time)
struct wlr_surface* surface = nullptr;
View_ptr view = view_at(
- cursor->mp_server,
- cursor->mp_wlr_cursor->x,
- cursor->mp_wlr_cursor->y,
+ mp_server,
+ mp_wlr_cursor->x,
+ mp_wlr_cursor->y,
&surface,
&sx, &sy
);
- if (!view && time) {
+ if (!surface && time)
wlr_xcursor_manager_set_cursor_image(
- cursor->mp_cursor_manager,
+ mp_cursor_manager,
"left_ptr",
- cursor->mp_wlr_cursor
+ mp_wlr_cursor
);
- }
- cursor_motion_to_client(cursor, view, surface, sx, sy, time);
+ cursor_motion_to_client(this, view, surface, sx, sy, time);
}
void
@@ -339,7 +341,7 @@ Cursor::handle_cursor_motion(struct wl_listener* listener, void* data)
= reinterpret_cast<struct wlr_event_pointer_motion*>(data);
wlr_cursor_move(cursor->mp_wlr_cursor, event->device, event->delta_x, event->delta_y);
- process_cursor_motion(cursor, event->time_msec);
+ cursor->process_cursor_motion(event->time_msec);
}
void
@@ -350,7 +352,7 @@ Cursor::handle_cursor_motion_absolute(struct wl_listener* listener, void* data)
= reinterpret_cast<struct wlr_event_pointer_motion_absolute*>(data);
wlr_cursor_warp_absolute(cursor->mp_wlr_cursor, event->device, event->x, event->y);
- process_cursor_motion(cursor, event->time_msec);
+ cursor->process_cursor_motion(event->time_msec);
}
bool
diff --git a/src/kranewl/model.cc b/src/kranewl/model.cc
@@ -32,8 +32,8 @@ extern "C" {
#include <wlr/types/wlr_surface.h>
}
#undef static
-#undef class
#undef namespace
+#undef class
Model::Model(
Config const& config,
@@ -241,12 +241,15 @@ Model::focus_view(View_ptr view)
{
TRACE();
+ if (!view || !view->mp_context)
+ return;
+
Output_ptr output = view->mp_context->output();
if (!output || mp_focus == view)
return;
- if (!view->sticky()) {
+ if (!view->sticky() || view->mp_context != mp_context) {
activate_workspace(view->mp_workspace);
mp_workspace->activate_view(view);
}
@@ -263,6 +266,36 @@ Model::focus_view(View_ptr view)
}
void
+Model::refocus()
+{
+ TRACE();
+
+ Output_ptr output;
+ if (!mp_focus || !(output = mp_focus->mp_context->output()))
+ return;
+
+ if (!mp_focus->sticky() || mp_focus->mp_context != mp_context) {
+ activate_workspace(mp_focus->mp_workspace);
+ mp_workspace->activate_view(mp_focus);
+ }
+
+ mp_focus->focus(Toggle::On);
+ mp_focus->set_urgent(false);
+
+ if (mp_workspace->layout_is_persistent() || mp_workspace->layout_is_single())
+ apply_layout(mp_workspace);
+}
+
+void
+Model::focus_output(Output_ptr output)
+{
+ TRACE();
+
+ if (output && output != mp_output)
+ focus_view(output->context()->workspace()->active());
+}
+
+void
Model::place_view(Placement& placement)
{
TRACE();
@@ -1840,8 +1873,8 @@ Model::destroy_view(View_ptr view)
TRACE();
m_view_map.erase(view->m_uid);
- delete view;
spdlog::info("Destroyed view {}", view->m_uid_formatted);
+ delete view;
}
Layer_ptr
@@ -1873,16 +1906,6 @@ Model::register_layer(Layer_ptr 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
@@ -67,8 +67,8 @@ extern "C" {
#endif
}
#undef static
-#undef class
#undef namespace
+#undef class
extern "C" {
#include <xkbcommon/xkbcommon.h>
@@ -427,8 +427,9 @@ Server::handle_new_layer_shell_surface(struct wl_listener* listener, void* data)
break;
default:
spdlog::error("No applicable scene layer found for layer surface");
+ spdlog::warn("Ignoring layer surface");
scene_layer = SCENE_LAYER_NONE;
- break;
+ return;
}
Output_ptr output = reinterpret_cast<Output_ptr>(layer_surface->output->data);
diff --git a/src/kranewl/tree/layer.cc b/src/kranewl/tree/layer.cc
@@ -1,13 +1,23 @@
#include <trace.hh>
+#include <kranewl/model.hh>
+#include <kranewl/server.hh>
#include <kranewl/tree/layer.hh>
+#include <kranewl/tree/output.hh>
// https://github.com/swaywm/wlroots/issues/682
+#include <pthread.h>
+#define class class_
#define namespace namespace_
+#define static
extern "C" {
#include <wlr/types/wlr_layer_shell_v1.h>
+#include <wlr/types/wlr_scene.h>
+#include <wlr/types/wlr_seat.h>
}
+#undef static
#undef namespace
+#undef class
Layer::Layer(
struct wlr_layer_surface_v1* layer_surface,
@@ -16,7 +26,8 @@ Layer::Layer(
Output_ptr output,
SceneLayer scene_layer
)
- : m_uid(reinterpret_cast<std::uintptr_t>(layer_surface)),
+ : Node(Type::LayerShell),
+ m_uid(reinterpret_cast<std::uintptr_t>(layer_surface)),
m_uid_formatted([this]() {
std::stringstream uid_ss;
uid_ss << "0x" << std::hex << m_uid;
@@ -31,12 +42,12 @@ Layer::Layer(
ml_unmap({ .notify = Layer::handle_unmap }),
ml_surface_commit({ .notify = Layer::handle_surface_commit }),
ml_destroy({ .notify = Layer::handle_destroy }),
- m_mapped(false),
+ m_mapped(0),
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->surface->events.commit, &ml_surface_commit);
wl_signal_add(&mp_layer_surface->events.destroy, &ml_destroy);
}
@@ -56,25 +67,119 @@ Layer::set_region(Region const& region)
}
void
-Layer::handle_map(struct wl_listener*, void*)
+Layer::handle_map(struct wl_listener* listener, void*)
{
+ TRACE();
+ Layer_ptr layer = wl_container_of(listener, layer, ml_map);
+
+ wlr_surface_send_enter(
+ layer->mp_layer_surface->surface,
+ layer->mp_layer_surface->output
+ );
+
+ if (layer->mp_server->m_seat.mp_cursor)
+ layer->mp_server->m_seat.mp_cursor->process_cursor_motion(0);
+}
+
+static inline void
+unmap_layer(Layer_ptr layer)
+{
+ TRACE();
+
+ layer->mp_layer_surface->mapped = 0;
+ struct wlr_seat* seat = layer->mp_server->m_seat.mp_wlr_seat;
+
+ if (layer->mp_layer_surface->surface == seat->keyboard_state.focused_surface)
+ layer->mp_model->refocus();
+
+ if (layer->mp_server->m_seat.mp_cursor)
+ layer->mp_server->m_seat.mp_cursor->process_cursor_motion(0);
}
void
-Layer::handle_unmap(struct wl_listener*, void*)
+Layer::handle_unmap(struct wl_listener* listener, void*)
{
+ TRACE();
+ Layer_ptr layer = wl_container_of(listener, layer, ml_unmap);
+ unmap_layer(layer);
}
void
-Layer::handle_surface_commit(struct wl_listener*, void*)
+Layer::handle_surface_commit(struct wl_listener* listener, void*)
{
+ TRACE();
+
+ Layer_ptr layer = wl_container_of(listener, layer, ml_surface_commit);
+
+ 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;
+ 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");
+ spdlog::warn("Not committing surface");
+ scene_layer = SCENE_LAYER_NONE;
+ return;
+ }
+
+ 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
-Layer::handle_destroy(struct wl_listener*, void*)
+Layer::handle_destroy(struct wl_listener* listener, void*)
{
+ TRACE();
+
+ Layer_ptr layer = wl_container_of(listener, layer, ml_destroy);
+ struct wlr_output* wlr_output = layer->mp_layer_surface->output;
+
+ if (layer->mp_layer_surface->mapped)
+ unmap_layer(layer);
+
+ wl_list_remove(&layer->ml_map.link);
+ wl_list_remove(&layer->ml_unmap.link);
+ wl_list_remove(&layer->ml_surface_commit.link);
+ wl_list_remove(&layer->ml_destroy.link);
+
+ Output_ptr output;
+ if (wlr_output && (output = reinterpret_cast<Output_ptr>(wlr_output->data))) {
+ output->remove_layer(layer);
+ output->arrange_layers();
+ layer->mp_layer_surface->output = nullptr;
+ }
+ spdlog::info("Destroyed layer {}", layer->m_uid_formatted);
+ delete layer;
}
diff --git a/src/kranewl/tree/node.cc b/src/kranewl/tree/node.cc
@@ -1,49 +0,0 @@
-#include <kranewl/tree/node.hh>
-
-Node::Node(Root_ptr root)
- : m_uid(reinterpret_cast<Uid>(root)),
- m_type(Type::Root),
- m_root(root),
- m_destroying(false),
- m_dirty(false),
- m_events{ .destroy = {} }
-{}
-
-Node::Node(Output_ptr output)
- : m_uid(reinterpret_cast<Uid>(output)),
- m_type(Type::Output),
- m_output(output),
- m_destroying(false),
- m_dirty(false),
- m_events{ .destroy = {} }
-{}
-
-Node::Node(Context_ptr context)
- : m_uid(reinterpret_cast<Uid>(context)),
- m_type(Type::Context),
- m_context(context),
- m_destroying(false),
- m_dirty(false),
- m_events{ .destroy = {} }
-{}
-
-Node::Node(Workspace_ptr workspace)
- : m_uid(reinterpret_cast<Uid>(workspace)),
- m_type(Type::Workspace),
- m_workspace(workspace),
- m_destroying(false),
- m_dirty(false),
- m_events{ .destroy = {} }
-{}
-
-Node::Node(Container_ptr container)
- : m_uid(reinterpret_cast<Uid>(container)),
- m_type(Type::Container),
- m_container(container),
- m_destroying(false),
- m_dirty(false),
- m_events{ .destroy = {} }
-{}
-
-Node::~Node()
-{}
diff --git a/src/kranewl/tree/output.cc b/src/kranewl/tree/output.cc
@@ -19,8 +19,8 @@ extern "C" {
#include <wlr/types/wlr_seat.h>
}
#undef static
-#undef class
#undef namespace
+#undef class
#include <vector>
@@ -31,8 +31,7 @@ Output::Output(
struct wlr_scene_output* wlr_scene_output,
Region const&& output_region
)
- : Node(this),
- mp_context(nullptr),
+ : mp_context(nullptr),
m_full_region(output_region),
m_placeable_region(output_region),
mp_server(server),
@@ -121,6 +120,13 @@ Output::handle_destroy(struct wl_listener*, void* data)
{
TRACE();
+ static const std::vector<SceneLayer> scene_layers = {
+ SCENE_LAYER_BACKGROUND,
+ SCENE_LAYER_BOTTOM,
+ SCENE_LAYER_TOP,
+ SCENE_LAYER_OVERLAY,
+ };
+
struct wlr_output* wlr_output = reinterpret_cast<struct wlr_output*>(data);
Output_ptr output = reinterpret_cast<Output_ptr>(wlr_output->data);
@@ -133,6 +139,15 @@ Output::handle_destroy(struct wl_listener*, void* data)
wlr_scene_output_destroy(output->mp_wlr_scene_output);
wlr_output_layout_remove(output->mp_server->mp_output_layout, output->mp_wlr_output);
+ for (SceneLayer scene_layer : scene_layers) {
+ for (Layer_ptr layer : output->m_layer_map.at(scene_layer)) {
+ layer->mp_output = nullptr;
+ layer->mp_layer_surface->output = nullptr;
+ }
+
+ output->m_layer_map.at(scene_layer).clear();
+ }
+
output->mp_model->unregister_output(output);
}
@@ -207,6 +222,16 @@ Output::remove_layer(Layer_ptr layer)
Util::erase_remove(m_layer_map.at(layer->m_scene_layer), layer);
}
+void
+Output::relayer_layer(Layer_ptr layer, SceneLayer old_layer, SceneLayer new_layer)
+{
+ TRACE();
+
+ Util::erase_remove(m_layer_map.at(old_layer), layer);
+ m_layer_map[new_layer].push_back(layer);
+ layer->m_scene_layer = new_layer;
+}
+
static inline void
propagate_exclusivity(
Region& placeable_region,
diff --git a/src/kranewl/tree/view.cc b/src/kranewl/tree/view.cc
@@ -19,8 +19,8 @@ extern "C" {
#include <wlr/util/edges.h>
}
#undef static
-#undef class
#undef namespace
+#undef class
View::View(
XDGView_ptr,
@@ -30,13 +30,13 @@ View::View(
Seat_ptr seat,
struct wlr_surface* wlr_surface
)
- : m_uid(uid),
+ : Node(Type::XDGShell),
+ m_uid(uid),
m_uid_formatted([uid]() {
std::stringstream uid_ss;
uid_ss << "0x" << std::hex << uid;
return uid_ss.str();
}()),
- m_type(Type::XDGShell),
mp_server(server),
mp_model(model),
mp_seat(seat),
@@ -88,8 +88,8 @@ View::View(
Seat_ptr seat,
struct wlr_surface* wlr_surface
)
- : m_uid(uid),
- m_type(Type::XWayland),
+ : Node(Type::XWaylandManaged),
+ m_uid(uid),
mp_server(server),
mp_model(model),
mp_seat(seat),
diff --git a/src/kranewl/tree/xdg_view.cc b/src/kranewl/tree/xdg_view.cc
@@ -22,8 +22,8 @@ extern "C" {
#include <wlr/types/wlr_xdg_shell.h>
}
#undef static
-#undef class
#undef namespace
+#undef class
XDGView::XDGView(
struct wlr_xdg_surface* wlr_xdg_surface,
diff --git a/src/kranewl/tree/xwayland_view.cc b/src/kranewl/tree/xwayland_view.cc
@@ -13,8 +13,8 @@ extern "C" {
#include <wlr/xwayland.h>
}
#undef static
-#undef class
#undef namespace
+#undef class
XWaylandView::XWaylandView(
struct wlr_xwayland_surface* wlr_xwayland_surface,